Ë
    ëÓ^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Ø€HˆjÔ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   € Ü�n‰n˜SÓ!ˆØˆŒØˆ
r   c                ó.   — | j                   j                  S )z6Get the filename from the underlying ModelWeightAsset.©Úvaluer   ©Úselfs    r   r   zModelWeightsBase.filenamea   ó   € ð �z‰z×"Ñ"Ð"r   c                ó.   — | j                   j                  S )z1Get the URL from the underlying ModelWeightAsset.)r&   r   r'   s    r   r   zModelWeightsBase.urlf   s   € ð �z‰z�~‰~Ð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 )z¬Get 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%   € ð ×!Ñ! (Ó+ˆÙ!ˆu�y‰yÐ+ tÐ+r   c                óD   — | j                  |«      }|r|j                  S dS )zºGet 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�~‰~Ð0¨DÐ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ÓD€IÜ�7‰7�?‰?œ2Ÿ7™7×-Ñ-¨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Ó3€Jô ×&Ñ& zÓ2€Eð €}Õ2ð	ÝKà$×2Ñ2°:Ó>ˆEð ÐØ�i‰iˆÙ)5�u—~’~¸4‰ð		ÝAà Ñ0Øà! *Ñ-ˆCØˆLô
 
‡w�w‡~�~Ð&Ô'±
Ù™LÜ%Ð&6¸ÔEÜ—‘Ø$Ð%5Ð$6ð 7_ð _ôð 	ô —‘˜eÐ$4Ð#5Ð5[Ð\Ô]Øä
‡K�KÐ5Ð6FÐ5GÐHÔIÜØØ!Ø!öøôI #ò 	Ø�w‰wÐ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é   € ô �7‰7�>‰>Ð*Ô+ÙÜ#Ð&IÐJZÐI[Ð$\Ó]Ð]Øô —‘×!Ñ!Ð"2Ó3€JÜ×&Ñ& zÓ2€Eà€}˜Ÿ™Ð.ä�‰Ð1°*°Ð=RÐSÔTØäÐ.°·±Ô?à-Ð.>Ð-?ð @GàGQÀlÐReðgð 	ñ
 Ü˜YÓ'Ð'ä�N‰N˜9Ô%Øä
‡L�LÐ-Ð.>Ð-?Ð@Ô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9�tô d9ôNdÐ#ô dóP:ðF ØðYØðYàðYð ðYð 
ó	Yõx)r   