
    .h%                        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        e/var/www/html/ai-service/venv/lib/python3.12/site-packages/ultralytics/solutions/similarity_search.py__init__zVisualAISearch.__init__2   s    ^Mm_\]^^y>;'(
((VZZ9:#FJJx$?@}}##%4NNdmm_,TU_T``klmAK8AN NDM%odkkJ

  "    c                    | j                   j                  t        j                  |            j	                         j                         S )z7Extract CLIP image embedding from the given image path.)r)   encode_imager   openr   numpy)r-   paths     r/   extract_image_featurez$VisualAISearch.extract_image_featureO   s2    zz&&uzz$'78<<>DDFFr1   c                    | j                   j                  | j                   j                  |g            j                         j	                         S )z6Extract CLIP text embedding from the given text query.)r)   encode_texttokenizer   r5   )r-   texts     r/   extract_text_featurez#VisualAISearch.extract_text_featureS   s:    zz%%djj&9&94&&ABFFHNNPPr1   c                   t        | j                        j                         rt        | 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)an  
        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   appendr7   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_indexW   s      !((*tD4F4F/G/N/N/PKK9:..t/?/?@DJ!wwt'9'9:D 	9: MM))+ 		=D{{  "))#.kA=t99$?@  ''		2		= HII))G$++I6

(ZZ++GMM!,<=


w

tzz4+;+;<
""BHHT-=-=$>?hs4#3#345X>?  =499+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 )
au  
        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 )Nr@    )xs    r/   <lambda>z'VisualAISearch.search.<locals>.<lambda>   s
    1Q4 r1   T)keyreversez
Ranked Results:z  - z | Similarity: z.4f)r<   rN   r   rO   r*   search	enumerater+   floatsortr   rA   )r-   queryksimilarity_thresh	text_featDr*   idxiresultsrJ   scorers                r/   ra   zVisualAISearch.search   s   " --e4;;IF	

	*::$$Y25BKERSHBU
8>QYZ[\Y]^aYbfwYwTa %!S	"23
 
 	6'(" 	AKD%KK$tfOE#;?@	A &&!&&
 's   ,D "D8Dc                $    | j                  |      S )z.Direct call interface for the search function.)ra   )r-   re   s     r/   __call__zVisualAISearch.__call__   s    {{5!!r1   N)r.   r   returnNone)r6   r   rq   
np.ndarray)r;   strrq   rs   )rq   rr   )   g?)re   rt   rf   intrg   rc   rq   	list[str])re   rt   rq   rw   )
__name__
__module____qualname____doc__r0   r7   r<   r,   ra   rp   r\   r1   r/   r   r      s*    :#:GQ+@Z'@"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)a  
        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   searcherrx   r   resolveappadd_url_ruler*   )r-   r   r   r   r   r   s         r/   r0   zSearchApp.__init__   sw     	>*99.&D@'t*,,.%	
 	cTZZ%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   re    zsimilarity-search.html)rl   )r   methodformr#   stripr   r   )r-   rl   re   s      r/   r*   zSearchApp.index   sc    <<&(LL%%))'26<<>EmmE*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   rt   r   rt   rq   rr   )rq   rt   )F)r   boolrq   rr   )rx   ry   rz   r{   r0   r*   r   r\   r1   r/   r}   r}      s    ,R,O"r1   r}   )
__future__r   ospathlibr   typingr   r5   rC   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%+

! "R" R"j7" 7"r1   