
    ^j>                        d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	 ddl
mZmZ ddlmZ  e       Zd	Zd
Z ed       G d d             Z G d de      Z G d de      ZddZ	 	 d	 	 	 	 	 	 	 ddZdddZy)a  Model weights abstraction and download system.

Provides forward-compatible pattern for model weights across rf-detr and rf-detr-plus packages. External packages (like
rf-detr-plus) should inherit from ModelWeightsBase to ensure compile-time interface compatibility.

Critical Strategic Decisions:
    1. **Standalone first**: Check local ModelWeights before lazy-importing external packages
    2. **Compile-time safety**: Inheritance-based compatibility via ModelWeightsBase
    3. **Clean abstraction**: Enum values ARE ModelWeightAsset dataclass instances
    4. **Backward compatible**: Legacy OPEN_SOURCE_MODELS dict maintained
    5. **Offline testable**: All I/O operations mockable

Download Priority Order:
    1. Local ModelWeights.from_filename() - rf-detr's built-in models
    2. rfdetr_plus.assets.ModelWeights.from_filename() - lazy import if not found locally
    3. PLATFORM_MODELS dict - legacy fallback for backward compatibility
    )annotationsN)	dataclass)Enum)_IS_RFDETR_PLUS_AVAILABLE)_download_file_validate_file_md5)
get_loggerRF_HOMEz~/.roboflow/modelsT)frozenc                  4    e Zd ZU dZded<   ded<   dZded<   y)ModelWeightAsseta  Dataclass representing a model asset with download information.

    This is the standard format for model assets across rf-detr packages. Both rf-detr and rf-detr-plus should use this
    structure for compatibility.

    Attributes:
        filename: The local filename for the model weights
        url: The download URL
        md5_hash: The expected MD5 hash for integrity validation (None if not available)

    Example:
        >>> asset = ModelWeightAsset(
        ...     filename='rf-detr-base.pth',
        ...     url='https://storage.googleapis.com/rfdetr/rf-detr-base-coco.pth',
        ...     md5_hash='b4d3ce46099eaed50626ede388caf979'
        ... )
    strfilenameurlN
str | Nonemd5_hash)__name__
__module____qualname____doc____annotations__r        f/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/rfdetr/assets/model_weights.pyr   r   (   s    $ M	HHjr   r   c                      e Zd ZdZddZedd       Zedd       Zedd       Ze	dd       Z
e	dd       Ze	dd       Ze	dd	       Zy
)ModelWeightsBasea  Base class for model weight registries.

    This base class ensures compile-time compatibility between rf-detr and rf-detr-plus. Both packages should inherit
    from this class to ensure they have the same interface.

    Each enum member's value must be a ModelWeightAsset instance.

    Example inheritance:
        >>> from rfdetr.assets import ModelWeightAsset
        >>> class MyModelWeights(ModelWeightsBase):
        ...     MODEL_NAME = ModelWeightAsset(
        ...         "model.pth",
        ...         "https://example.com/model.pth",
        ...         "abc123"
        ...     )

    Example usage:
        >>> from rfdetr.assets.model_weights import ModelWeights
        >>> asset = ModelWeights.from_filename("rf-detr-base.pth")
        >>> asset.filename
        'rf-detr-base.pth'
        >>> asset.url  # doctest: +SKIP
        'https://storage.googleapis.com/rfdetr/rf-detr-base-coco.pth'
    c                >    t         j                  |       }||_        |S )N)object__new___value_)clsassetobjs      r   r   zModelWeightsBase.__new__[   s    nnS!
r   c                .    | j                   j                  S )z6Get the filename from the underlying ModelWeightAsset.valuer   selfs    r   r   zModelWeightsBase.filenamea        zz"""r   c                .    | j                   j                  S )z1Get the URL from the underlying ModelWeightAsset.)r&   r   r'   s    r   r   zModelWeightsBase.urlf   s     zz~~r   c                .    | j                   j                  S )z6Get the MD5 hash from the underlying ModelWeightAsset.)r&   r   r'   s    r   r   zModelWeightsBase.md5_hashk   r)   r   c                `    | D ])  }|j                   j                  |k(  s|j                   c S  y)a  Get ModelWeightAsset by filename.

        Args:
            filename: The model filename (e.g., 'rf-detr-base.pth')

        Returns:
            ModelWeightAsset instance if found, None otherwise

        Example:
            >>> asset = ModelWeights.from_filename('rf-detr-base.pth')
            >>> asset.url
            'https://storage.googleapis.com/rfdetr/rf-detr-base-coco.pth'
        Nr%   )r!   r   members      r   from_filenamezModelWeightsBase.from_filenamep   s4      	$F||$$0||#	$ r   c                D    | j                  |      }|r|j                  S dS )zGet download URL for a model by filename.

        Args:
            filename: The model filename

        Returns:
            URL string if found, None otherwise
        N)r.   r   r!   r   r"   s      r   get_urlzModelWeightsBase.get_url   s%     !!(+!uyy+t+r   c                D    | j                  |      }|r|j                  S dS )zGet expected MD5 hash for a model by filename.

        Args:
            filename: The model filename

        Returns:
            MD5 hash string if available, None otherwise
        N)r.   r   r0   s      r   get_md5zModelWeightsBase.get_md5   s%     !!(+!&u~~0D0r   c                T    | D cg c]  }|j                   j                   c}S c c}w )zbList all available model filenames.

        Returns:
            List of model filenames
        r%   )r!   r-   s     r   list_modelszModelWeightsBase.list_models   s"     588&%%888s   %N)r"   r   returnz'ModelWeightsBase'r6   r   )r6   r   )r   r   r6   zModelWeightAsset | None)r   r   r6   r   )r6   z	list[str])r   r   r   r   r   propertyr   r   r   classmethodr.   r1   r3   r5   r   r   r   r   r   A   s    2 # #   # #  & 
, 
, 
1 
1 9 9r   r   c                  P   e Zd ZdZ eddd      Z eddd      Z edd	d
      Z eddd      Z eddd      Z	 eddd      Z
 eddd      Z eddd      Z eddd      Z eddd      Z ed d!d"      Z ed#d$d%      Z ed&d'd(      Z ed)d*d+      Z ed,d-d.      Z ed/d0d1      Zy2)3ModelWeightsa-  Enumeration of available RF-DETR model assets.

    Inherits from ModelWeightsBase to ensure compatibility with rf-detr-plus.

    Each enum member's value is a ModelWeightAsset instance containing:
    - filename: The local filename for the model weights
    - url: The download URL
    - md5_hash: The expected MD5 hash for integrity validation

    Example:
        >>> asset = ModelWeights.RF_DETR_BASE
        >>> asset.filename
        'rf-detr-base.pth'
        >>> asset.url
        'https://storage.googleapis.com/rfdetr/rf-detr-base-coco.pth'
    zrf-detr-base.pthz;https://storage.googleapis.com/rfdetr/rf-detr-base-coco.pth b4d3ce46099eaed50626ede388caf979zrf-detr-base-o365.pthz]https://storage.googleapis.com/rfdetr/top-secret-1234/lwdetr_dinov2_small_o365_checkpoint.pth d93f4921ccbb0f0a2e4364bed290892bzrf-detr-base-2.pthz8https://storage.googleapis.com/rfdetr/rf-detr-base-2.pth 462f4d9df407ddc1812f42614040e913zrf-detr-large.pthz7https://storage.googleapis.com/rfdetr/rf-detr-large.pth 992c8e862aa733a7bb2777e45d49f1a0zrf-detr-large-2026.pthz<https://storage.googleapis.com/rfdetr/rf-detr-large-2026.pth 5cb72153541cbcb9aa6efa26222acc75zrf-detr-nano.pthzKhttps://storage.googleapis.com/rfdetr/nano_coco/checkpoint_best_regular.pth fb6504cce7fbdc783f7a46991f07639fzrf-detr-small.pthzLhttps://storage.googleapis.com/rfdetr/small_coco/checkpoint_best_regular.pth fb37061c1af7bace359c91b723a8d5c1zrf-detr-medium.pthzMhttps://storage.googleapis.com/rfdetr/medium_coco/checkpoint_best_regular.pth 7223f764a87b863f02eb8d52bf0ce2eez#rf-detr-keypoint-preview-xlarge.pthzIhttps://storage.googleapis.com/rfdetr/rf-detr-keypoint-preview-xlarge.pth 6de511943ee85a547d4c5cb527daf0ebzrf-detr-seg-preview.ptz<https://storage.googleapis.com/rfdetr/rf-detr-seg-preview.pt e35820c28fb86080558123e47a5e49cazrf-detr-seg-nano.ptz:https://storage.googleapis.com/rfdetr/rf-detr-seg-n-ft.pth 9995497791d0ff1664a1d9ddee9cfd20zrf-detr-seg-small.ptz:https://storage.googleapis.com/rfdetr/rf-detr-seg-s-ft.pth 0a2a3006381d0c42853907e700eadd08zrf-detr-seg-medium.ptz:https://storage.googleapis.com/rfdetr/rf-detr-seg-m-ft.pth a49af1562c3719227ad43d0ca53b4c7azrf-detr-seg-large.ptz:https://storage.googleapis.com/rfdetr/rf-detr-seg-l-ft.pth 275f7b094909544ed2841c94a677d07ezrf-detr-seg-xlarge.ptz;https://storage.googleapis.com/rfdetr/rf-detr-seg-xl-ft.pth 3693b35d0eea86ebb3e0444f4a611fbazrf-detr-seg-xxlarge.ptz<https://storage.googleapis.com/rfdetr/rf-detr-seg-2xl-ft.pth 040bc3412af840fa8a47e0ff69b552baN)r   r   r   r   r   RF_DETR_BASERF_DETR_BASE_O365RF_DETR_BASE_2RF_DETR_LARGERF_DETR_LARGE_2026RF_DETR_NANORF_DETR_SMALLRF_DETR_MEDIUMRF_DETR_KEYPOINT_PREVIEWRF_DETR_SEG_PREVIEWRF_DETR_SEG_NANORF_DETR_SEG_SMALLRF_DETR_SEG_MEDIUMRF_DETR_SEG_LARGERF_DETR_SEG_XLARGERF_DETR_SEG_XXLARGEr   r   r   r;   r;      sa   $ $E*L
 )g*
 &B*N
 %A*M
 * F*
 $U*L
 %V*M
 &W*N
  0-S*  + F*
 (D*
 )D*
 *D*
 )D*
 *E*
 + F*r   r;   c                     t         j                  j                  t        t              } t         j
                  j                  t         j
                  j                  |             S )u-  Return the directory where RF-DETR caches downloaded model weights.

    Reads the ``RF_HOME`` environment variable; defaults to ``~/.roboflow/models`` when the variable is not set.

    Set ``RF_HOME`` to override the cache location for all RF-DETR models:

    .. code-block:: bash

        export RF_HOME=/mnt/shared/models

    Args: None

    Returns:
        Absolute, user-expanded path to the model cache directory.  The directory is *not* created by this function —
        callers that need it to exist should call ``os.makedirs(get_model_cache_dir(), exist_ok=True)`` themselves.

    Examples:
        >>> import os
        >>> _ = os.environ.pop("RF_HOME", None)  # ensure default
        >>> expected = os.path.normpath(os.path.expanduser("~/.roboflow/models"))
        >>> get_model_cache_dir() == expected
        True
        >>> os.environ["RF_HOME"] = "~/rfdetr_cache"
        >>> expected = os.path.normpath(os.path.expanduser("~/rfdetr_cache"))
        >>> get_model_cache_dir() == expected
        True
        >>> del os.environ["RF_HOME"]
    )osenvironget_RF_HOME_ENV_VAR_DEFAULT_CACHE_DIRpathabspath
expanduser)	cache_dirs    r   get_model_cache_dirrf     s<    : 

/1CDI77??277--i899r   c                   d}t         j                  j                  |       }t        j	                  |      }|t
        r	 ddlm} |j	                  |      }||j                  }|r|j                  nd}n	 ddlm}	 ||	vry|	|   }d}t         j                  j                  |       rF|sD|rA|r?t!        | |      st"        j%                  d|  d       yt"        j'                  d|  d	       yt"        j'                  d
|         t)        || |       y# t        $ r}|j                  dvr Y d}~d}~ww xY w# t        t        f$ r Y yw xY w)a  Download pretrained weights with optional MD5 validation.

    Download Priority Order:
        The function searches for models in the following order, stopping at the first match:

        1. **Local ModelWeights** (primary source):
           - Checks rf-detr's built-in ModelWeights enum
           - Ensures rf-detr works completely standalone
           - No unnecessary imports or performance overhead

        2. **External packages** (lazy import):
           - Only attempts import if model not found locally
           - Tries rf-detr-plus.assets.ModelWeights if installed
           - Gracefully handles missing packages (ImportError/AttributeError)

        3. **Legacy platform models** (backward compatibility):
           - Falls back to PLATFORM_MODELS dict for older models
           - Maintains compatibility with existing deployments
           - No MD5 validation for legacy models

    Args:
        pretrain_weights: Name of the pretrained weights file (e.g., 'rf-detr-base.pth')
        redownload: Force re-download even if file exists
        validate_md5: Whether to validate MD5 hash of downloaded file

    Example:
        >>> download_pretrain_weights('rf-detr-base.pth')  # doctest: +SKIP
        Downloading pretrained weights for rf-detr-base.pth
    Nr   )r;   >   rfdetr_plus.assetsrfdetr_plus)PLATFORM_MODELSzExisting file u    has incorrect MD5 hash. It may be a user-provided checkpoint or a corrupted/tampered file — skipping re-download to avoid overwriting it. To force a fresh download of the original weights, pass redownload=True.zFile z& already exists with correct MD5 hash.z#Downloading pretrained weights for )r   r   expected_md5)r]   rb   basenamer;   r.   r   rfdetr_plus.assetsModuleNotFoundErrornamer   r   rfdetr.platform.downloadsrj   ImportErrorKeyErrorexistsr   loggerwarninginfor   )
pretrain_weights
redownloadvalidate_md5r"   
model_namePlusModelWeightsexr   rk   rj   s
             r   download_pretrain_weightsr}   1  se   D &*E !!"23J &&z2E }2	K$22:>E ii)5u~~4		A0!*-CL
 
ww~~&'
L%&6E$%5$6 7_ _ 	 e$4#55[\]
KK56F5GHI!!I # 	wwCC D	$ X& 		s0    D 7
D: D: 	D7D22D7:EEc                   t         j                  j                  |       s|rt        d|        yt         j                  j	                  |       }t
        j                  |      }||j                  t        j                  d| d       yt        | |j                        s,d|  d| d}|rt        |      t        j                  |       yt        j                  d	|         y)
a  Validate MD5 hash of pretrained weights file.

    Args:
        pretrain_weights: Path to the pretrained weights file
        strict: If True, raise error on validation failure. If False, just warn.

    Returns:
        True if validation passes or no hash is available, False otherwise

    Raises:
        ValueError: If strict=True and validation fails
        FileNotFoundError: If strict=True and file doesn't exist
    z#Pretrained weights file not found: FzNo MD5 hash available for z, skipping validationTzMD5 hash validation failed for zf. The file may be corrupted or tampered with. Consider re-downloading with download_pretrain_weights('z', redownload=True)zMD5 validation passed for )r]   rb   rs   FileNotFoundErrorrl   r;   r.   r   rt   debugr   
ValueErrorru   )rw   strictrz   r"   	error_msgs        r   validate_pretrain_weightsr     s     77>>*+#&IJZI[$\]] !!"23J&&z2E}.1*=RST.?-.>-? @GGQlReg 	
 Y''NN9%
LL-.>-?@Ar   r7   )FT)rw   r   rx   boolry   r   r6   None)F)rw   r   r   r   r6   r   )r   
__future__r   r]   dataclassesr   enumr   rfdetr.platformr   rfdetr.utilities.filesr   r   rfdetr.utilities.loggerr	   rt   r`   ra   r   r   r;   rf   r}   r   r   r   r   <module>r      s   $ # 	 !  5 E .	 )  $     0d9t d9Nd# dP:F YYY Y 
	Yx)r   