Ë
    Fêñi¬%  ã                  óÂ   — d dl mZ d dlZd dlm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mZ d dlmZ d d	lmZmZ d
ej*                  d<    G d„ d«      Z G d„ d«      Zy)é    )ÚannotationsN)ÚPath)ÚAny)ÚImage)ÚIMG_FORMATS)ÚLOGGERÚTORCH_VERSION)Úcheck_requirements)Ú	TORCH_2_4Úselect_deviceÚTRUEÚKMP_DUPLICATE_LIB_OKc                  óB   — e Zd ZdZd	d„Zd
d„Zdd„Zdd„Zddd„Zdd„Z	y)ÚVisualAISearcha  A semantic image search system that leverages OpenCLIP for generating high-quality image and text embeddings and
    FAISS for fast similarity-based retrieval.

    This class aligns image and text embeddings in a shared semantic space, enabling users to search large collections
    of images using natural language queries with high accuracy and speed.

    Attributes:
        data (str): Directory containing images.
        device (str): Computation device, e.g., 'cpu' or 'cuda'.
        faiss_index (str): Path to the FAISS index file.
        data_path_npy (str): Path to the numpy file storing image paths.
        data_dir (Path): Path object for the data directory.
        model: Loaded CLIP model.
        index: FAISS index for similarity search.
        image_paths (list[str]): List of image file paths.

    Methods:
        extract_image_feature: Extract CLIP embedding from an image.
        extract_text_feature: Extract CLIP embedding from text.
        load_or_build_index: Load existing FAISS index or build new one.
        search: Perform semantic search for similar images.

    Examples:
        Initialize and search for images
        >>> searcher = VisualAISearch(data="path/to/images", device="cuda")
        >>> results = searcher.search("a cat sitting on a chair", k=10)
    c                óL  — t         sJ dt        › d�«       ‚ddlm} t	        d«       t        d«      | _        d| _        d| _        t        |j                  d	d
«      «      | _        t        |j                  dd«      «      | _        | j                  j                  «       sOddlm} t#        j$                  | j                  › d|› d�«       ddlm}  ||› d�dd¬«       t        d
«      | _         |d| j                  ¬«      | _        d| _        g | _        | j1                  «        y)zDInitialize the VisualAISearch class with FAISS index and CLIP model.z1VisualAISearch requires torch>=2.4 (found torch==ú)r   )Úbuild_text_modelz	faiss-cpuÚfaisszfaiss.indexz	paths.npyÚdataÚimagesÚdeviceÚcpu)Ú
ASSETS_URLz( not found. Downloading images.zip from z/images.zip)Úsafe_downloadTé   )ÚurlÚunzipÚretryzclip:ViT-B/32)r   N)r   r	   Úultralytics.nn.text_modelr   r
   Ú
__import__r   Úfaiss_indexÚdata_path_npyr   ÚgetÚdata_dirr   r   ÚexistsÚultralytics.utilsr   r   ÚwarningÚultralytics.utils.downloadsr   ÚmodelÚindexÚimage_pathsÚload_or_build_index)ÚselfÚkwargsr   r   r   s        úi/var/www/pod-logistic/pod-ai/venv/lib/python3.12/site-packages/ultralytics/solutions/similarity_search.pyÚ__init__zVisualAISearch.__init__1   sñ   € åÐ^ÐMÌmÈ_Ð\]Ð^Ó^ˆyÝ>ä˜;Ô'ä Ó(ˆŒ
Ø(ˆÔØ(ˆÔÜ˜VŸZ™Z¨°Ó9Ó:ˆŒÜ# F§J¡J¨x¸Ó$?Ó@ˆŒà�}‰}×#Ñ#Ô%Ý4ä�N‰N˜dŸm™m˜_Ð,TÐU_ÐT`Ð`kÐlÔmÝAá  ¨KÐ8ÀÈAÕNÜ  ›NˆDŒMá% o¸d¿k¹kÔJˆŒ
àˆŒ
ØˆÔà× Ñ Õ"ó    c                ó²   — | j                   j                  t        j                  |«      «      j	                  «       j                  «       j                  «       S )z7Extract CLIP image embedding from the given image path.)r)   Úencode_imager   ÚopenÚdetachr   Únumpy)r-   Úpaths     r/   Úextract_image_featurez$VisualAISearch.extract_image_featureN   s;   € à�z‰z×&Ñ&¤u§z¡z°$Ó'7Ó8×?Ñ?ÓA×EÑEÓG×MÑMÓOÐOr1   c                óÀ   — | j                   j                  | j                   j                  |g«      «      j                  «       j	                  «       j                  «       S )z6Extract CLIP text embedding from the given text query.)r)   Úencode_textÚtokenizer5   r   r6   )r-   Útexts     r/   Úextract_text_featurez#VisualAISearch.extract_text_featureR   sC   € à�z‰z×%Ñ% d§j¡j×&9Ñ&9¸4¸&Ó&AÓB×IÑIÓK×OÑOÓQ×WÑWÓYÐYr1   c                ó‚  — t        | j                  «      j                  «       r‡t        | j                  «      j                  «       rdt	        j
                  d«       | j                  j                  | j                  «      | _        t        j                  | j                  «      | _        yt	        j
                  d«       g }| j                  j                  «       D ]x  }|j                  j                  «       j!                  d«      t"        vrŒ3	 |j%                  | j'                  |«      «       | j                  j%                  |j(                  «       Œz |st/        d«      ‚t        j0                  |«      j3                  d«      }| j                  j5                  |«       | j                  j7                  |j8                  d	   «      | _        | j                  j;                  |«       | j                  j=                  | j                  | j                  «       t        j>                  | j                  t        j@                  | j                  «      «       t	        j
                  d
tC        | j                  «      › d�«       y# t*        $ r0}t	        j,                  d|j(                  › d|› �«       Y d}~�ŒÝd}~ww xY w)ae  Load existing FAISS index or build a new one from image features.

        Checks if FAISS index and image paths exist on disk. If found, loads them directly. Otherwise, builds a new
        index by extracting features from all images in the data directory, normalizes the features, and saves both the
        index and image paths for future use.
        zLoading existing FAISS index...Nz#Building FAISS index from images...ú.z	Skipping z: z'No image embeddings could be generated.Úfloat32é   zIndexed z images.)"r   r!   r%   r"   r   Úinfor   Ú
read_indexr*   ÚnpÚloadr+   r$   ÚiterdirÚsuffixÚlowerÚlstripr   Úappendr8   ÚnameÚ	Exceptionr'   ÚRuntimeErrorÚvstackÚastypeÚnormalize_L2ÚIndexFlatIPÚshapeÚaddÚwrite_indexÚsaveÚarrayÚlen)r-   ÚvectorsÚfileÚes       r/   r,   z"VisualAISearch.load_or_build_indexV   sü  € ô �× Ñ Ó!×(Ñ(Ô*¬t°D×4FÑ4FÓ/G×/NÑ/NÔ/PÜ�K‰KÐ9Ô:ØŸ™×.Ñ.¨t×/?Ñ/?Ó@ˆDŒJÜ!Ÿw™w t×'9Ñ'9Ó:ˆDÔØô 	�‰Ð9Ô:Øˆð —M‘M×)Ñ)Ó+ò 		=ˆDà�{‰{× Ñ Ó"×)Ñ)¨#Ó.´kÑAØð=à—‘˜t×9Ñ9¸$Ó?Ô@Ø× Ñ ×'Ñ'¨¯	©	Õ2ð		=ñ ÜÐHÓIÐIä—)‘)˜GÓ$×+Ñ+¨IÓ6ˆØ�
‰
×Ñ Ô(à—Z‘Z×+Ñ+¨G¯M©M¸!Ñ,<Ó=ˆŒ
Ø�
‰
�‰�wÔØ�
‰
×Ñ˜tŸz™z¨4×+;Ñ+;Ô<Ü
�‰�×"Ñ"¤B§H¡H¨T×-=Ñ-=Ó$>Ô?ä�‰�hœs 4×#3Ñ#3Ó4Ð5°XÐ>Õ?øô ò =Ü—‘ ¨4¯9©9¨+°R¸°sÐ;×<Ò<ûð=ús   ÄAJÊ	J>Ê%J9Ê9J>c           	     ó$  — | j                  |«      j                  d«      }| j                  j                  |«       | j                  j                  ||«      \  }}t        |d   «      D ��cg c]1  \  }}|d   |   |k\  sŒ| j                  |   t        |d   |   «      f‘Œ3 }	}}|	j                  d„ d¬«       t        j                  d«       |	D ]!  \  }
}t        j                  d|
› d|d	›�«       Œ# |	D �cg c]  }|d   ‘Œ	 c}S c c}}w c c}w )
al  Return top-k semantically similar images to the given query.

        Args:
            query (str): Natural language text query to search for.
            k (int, optional): Maximum number of results to return.
            similarity_thresh (float, optional): Minimum similarity threshold for filtering results.

        Returns:
            (list[str]): List of image filenames ranked by similarity score.

        Examples:
            Search for images matching a query
            >>> searcher = VisualAISearch(data="images")
            >>> results = searcher.search("red car", k=5, similarity_thresh=0.2)
        r@   r   c                ó   — | d   S )NrA   © )Úxs    r/   ú<lambda>z'VisualAISearch.search.<locals>.<lambda>™   s
   €  1 Q¡4€ r1   T)ÚkeyÚreversez
Ranked Results:z  - z | Similarity: z.4f)r=   rO   r   rP   r*   ÚsearchÚ	enumerater+   ÚfloatÚsortr   rB   )r-   ÚqueryÚkÚsimilarity_threshÚ	text_featÚDr*   ÚidxÚiÚresultsrK   ÚscoreÚrs                r/   rb   zVisualAISearch.search‚   s  € ð  ×-Ñ-¨eÓ4×;Ñ;¸IÓFˆ	Ø�
‰
×Ñ 	Ô*à—:‘:×$Ñ$ Y°Ó2‰ˆˆ5äBKÈEÐRSÉHÓBU÷
Ù8>¸¸QÐYZÐ[\ÑY]Ð^aÑYbÐfwÓYwˆT×Ñ˜aÑ ¤%¨¨!©¨S©	Ó"2Ò3ð
ˆñ 
ð 	�‰™°ˆÔ6ä�‰Ð'Ô(Ø"ò 	A‰KˆD�%Ü�K‰K˜$˜t˜f O°E¸#°;Ð?Õ@ð	Að &Ö&˜��!“Ò&Ð&ùó
ùò 's   Á,DÂ "DÃ8Dc                ó$   — | j                  |«      S )z.Direct call interface for the search function.)rb   )r-   rf   s     r/   Ú__call__zVisualAISearch.__call__¡   s   € à�{‰{˜5Ó!Ð!r1   N)r.   r   ÚreturnÚNone)r7   r   rr   ú
np.ndarray)r<   Ústrrr   rt   )rr   rs   )é   gš™™™™™¹?)rf   ru   rg   Úintrh   rd   rr   ú	list[str])rf   ru   rr   rx   )
Ú__name__Ú
__module__Ú__qualname__Ú__doc__r0   r8   r=   r,   rb   rq   r]   r1   r/   r   r      s)   „ ñó8#ó:PóZó*@ôX'ô>"r1   r   c                  ó,   — e Zd ZdZddd„Zdd„Zd	d
d„Zy)Ú	SearchAppa  A Flask-based web interface for semantic image search with natural language queries.

    This class provides a clean, responsive frontend that enables users to input natural language queries and instantly
    view the most relevant images retrieved from the indexed database.

    Attributes:
        render_template: Flask template rendering function.
        request: Flask request object.
        searcher (VisualAISearch): Instance of the VisualAISearch class.
        app (Flask): Flask application instance.

    Methods:
        index: Process user queries and display search results.
        run: Start the Flask web application.

    Examples:
        Start a search application
        >>> app = SearchApp(data="path/to/images", device="cuda")
        >>> app.run(debug=True)
    Nc                ó  — t        d«       ddlm}m}m} || _        || _        t        ||¬«      | _         |t        dt        |«      j                  «       d¬«      | _
        | j                  j                  d| j                  d	d
g¬«       y)zýInitialize the SearchApp with VisualAISearch backend.

        Args:
            data (str, optional): Path to directory containing images to index and search.
            device (str, optional): Device to run inference on (e.g. 'cpu', 'cuda').
        zflask>=3.0.1r   )ÚFlaskÚrender_templateÚrequest)r   r   Ú	templatesz/images)Útemplate_folderÚstatic_folderÚstatic_url_pathú/ÚGETÚPOST)Ú	view_funcÚmethodsN)r
   Úflaskr€   r�   r‚   r   Úsearcherry   r   ÚresolveÚappÚadd_url_ruler*   )r-   r   r   r€   r�   r‚   s         r/   r0   zSearchApp.__init__¼   sw   € ô 	˜>Ô*ß9Ñ9à.ˆÔØˆŒÜ&¨D¸Ô@ˆŒÙÜØ'Ü˜t›*×,Ñ,Ó.Ø%ô	
ˆŒð 	�‰×Ñ˜c¨T¯Z©ZÀ%ÈÀÐÕQr1   c                óè   — g }| j                   j                  dk(  rE| j                   j                  j                  dd«      j	                  «       }| j                  |«      }| j                  d|¬«      S )zCProcess user query and display search results in the web interface.r‰   rf   Ú zsimilarity-search.html)rm   )r‚   ÚmethodÚformr#   Ústripr�   r�   )r-   rm   rf   s      r/   r*   zSearchApp.indexÑ   sc   € àˆØ�<‰<×Ñ &Ò(Ø—L‘L×%Ñ%×)Ñ)¨'°2Ó6×<Ñ<Ó>ˆEØ—m‘m EÓ*ˆGØ×#Ñ#Ð$<ÀgÐ#ÓNÐNr1   c                ó<   — | j                   j                  |¬«       y)z'Start the Flask web application server.)ÚdebugN)r�   Úrun)r-   r—   s     r/   r˜   zSearchApp.runÙ   s   € à�‰�‰˜5ˆÕ!r1   )r   N)r   ru   r   z
str | Nonerr   rs   )rr   ru   )F)r—   Úboolrr   rs   )ry   rz   r{   r|   r0   r*   r˜   r]   r1   r/   r~   r~   ¦   s   „ ñô*Ró*Oõ"r1   r~   )Ú
__future__r   ÚosÚpathlibr   Útypingr   r6   rD   ÚPILr   Úultralytics.data.utilsr   r&   r   r	   Úultralytics.utils.checksr
   Úultralytics.utils.torch_utilsr   r   Úenvironr   r~   r]   r1   r/   ú<module>r£      sK   ðõ #ã 	Ý Ý ã Ý å .ß 3Ý 7ß Bà%+€‡
�
Ð!Ñ "÷O"ñ O"÷d5"ò 5"r1   