
    ?h                         d Z ddlZddlmZmZ ddlmZ ddlmZm	Z	 ddl
mZmZmZmZmZmZmZmZmZmZmZmZmZ  G d d	e      Zy)
z
GraphQL `Aggregate` command.
    N)ListOptional)
Connection)_capitalize_first_letterfile_encoder_b64   )WhereGraphQLFilter	NearAudio	NearDepth	NearImageNearIMU
NearObjectNearTextNearThermal
NearVector	NearVideo	MediaTypec                   Z    e Zd ZdZdedef fdZdedd fdZddZd	e	dd fd
Z
d	e	dd fdZdedd fdZdedd fdZdee   dd fdZdedd fdZdedd fdZdedd fdZddededd fdZddededd fdZddededd fdZddededd fdZddededd fdZddededd fdZdefdZ xZS )AggregateBuilderzD
    AggregateBuilder class used to aggregate Weaviate objects.
    
class_name
connectionc                     t         |   |       t        |      | _        d| _        d| _        g | _        d| _        d| _        d| _	        d| _
        d| _        d| _        y)a2  
        Initialize a AggregateBuilder class instance.

        Parameters
        ----------
        class_name : str
            Class name of the objects to be aggregated.
        connection : weaviate.connect.Connection
            Connection object to an active and running Weaviate instance.
        NF)super__init__r   _class_name_object_limit_with_meta_count_fields_where_group_by_properties_uses_filter_near_tenant_limit)selfr   r   	__class__s      T/home/chris/cleankitchens-env/lib/python3.12/site-packages/weaviate/gql/aggregate.pyr   zAggregateBuilder.__init__"   sb     	$ 8 D,0&+"$'+9=!"''+
&*%)    tenantreturnc                 X    t        |t              st        d      || _        d| _        | S )zSets a tenant for the query.ztenant must be of type strT)
isinstancestr	TypeErrorr%   r#   )r'   r+   s     r)   with_tenantzAggregateBuilder.with_tenant:   s,    &#&899 r*   c                     d| _         | S )z
        Set Meta Count to True.

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            Updated AggregateBuilder.
        T)r   )r'   s    r)   with_meta_countz AggregateBuilder.with_meta_countC   s     !%r*   limitc                     || _         | S )a]  
        Set objectLimit to limit vector search results used within the aggregation query
        only when with near<MEDIA> filter.

        Parameters
        ----------
        limit : int
            The object limit.

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            Updated AggregateBuilder.
        )r   r'   r4   s     r)   with_object_limitz"AggregateBuilder.with_object_limitP   s      #r*   c                     || _         | S )a(  
        Set limit to limit the number of returned results from the aggregation query.

        Parameters
        ----------
        limit : int
            The limit.

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            Updated AggregateBuilder.
        )r&   r6   s     r)   
with_limitzAggregateBuilder.with_limitc   s     r*   fieldc                 <    | j                   j                  |       | S )aM  
        Include a field in the aggregate query.

        Parameters
        ----------
        field : str
            Field to include in the aggregate query.
            e.g. '<property_name> { count }'

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            Updated AggregateBuilder.
        )r    append)r'   r:   s     r)   with_fieldszAggregateBuilder.with_fieldsu   s      	E"r*   contentc                 4    t        |      | _        d| _        | S )a  
        Set 'where' filter.

        Parameters
        ----------
        content : dict
            The where filter to include in the aggregate query. See examples below.

        Examples
        --------
        The `content` prototype is like this:

        >>> content = {
        ...     'operator': '<operator>',
        ...     'operands': [
        ...         {
        ...             'path': [path],
        ...             'operator': '<operator>'
        ...             '<valueType>': <value>
        ...         },
        ...         {
        ...             'path': [<matchPath>],
        ...             'operator': '<operator>',
        ...             '<valueType>': <value>
        ...         }
        ...     ]
        ... }

        This is a complete `where` filter but it does not have to be like this all the time.

        Single operand:

        >>> content = {
        ...     'path': ["wordCount"],    # Path to the property that should be used
        ...     'operator': 'GreaterThan',  # operator
        ...     'valueInt': 1000       # value (which is always = to the type of the path property)
        ... }

        Or

        >>> content = {
        ...     'path': ["id"],
        ...     'operator': 'Equal',
        ...     'valueString': "e5dc4a4c-ef0f-3aed-89a3-a73435c6bbcf"
        ... }

        Multiple operands:

        >>> content = {
        ...     'operator': 'And',
        ...     'operands': [
        ...         {
        ...             'path': ["wordCount"],
        ...             'operator': 'GreaterThan',
        ...             'valueInt': 1000
        ...         },
        ...         {
        ...             'path': ["wordCount"],
        ...             'operator': 'LessThan',
        ...             'valueInt': 1500
        ...         }
        ...     ]
        ... }

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            Updated AggregateBuilder.
        T)r	   r!   r#   r'   r>   s     r)   
with_wherezAggregateBuilder.with_where   s    N Gn r*   
propertiesc                 "    || _         d| _        | S )a  
        Add a group by filter to the query. Might requires the user to set
        an additional group by clause using `with_fields(..)`.

        Parameters
        ----------
        properties : list of str
            list of properties that are included in the group by filter.
            Generates a filter like: 'groupBy: ["property1", "property2"]'
            from a list ["property1", "property2"]

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            Updated AggregateBuilder.
        T)r"   r#   )r'   rB   s     r)   with_group_by_filterz%AggregateBuilder.with_group_by_filter   s    $ %/! r*   c                 b    | j                   t        d      t        |      | _         d| _        | S )a  
        Set `nearText` filter. This filter can be used with text modules (text2vec).
        E.g.: text2vec-contextionary, text2vec-transformers.
        NOTE: The 'autocorrect' field is enabled only with the `text-spellcheck` Weaviate module.

        Parameters
        ----------
        content : dict
            The content of the `nearText` filter to set. See examples below.

        Examples
        --------
        Content full prototype:

        >>> content = {
        ...     'concepts': <list of str or str>,
        ...     # certainty ONLY with `cosine` distance specified in the schema
        ...     'certainty': <float>, # Optional, either 'certainty' OR 'distance'
        ...     'distance': <float>, # Optional, either 'certainty' OR 'distance'
        ...     'moveAwayFrom': { # Optional
        ...         'concepts': <list of str or str>,
        ...         'force': <float>
        ...     },
        ...     'moveTo': { # Optional
        ...         'concepts': <list of str or str>,
        ...         'force': <float>
        ...     },
        ...     'autocorrect': <bool>, # Optional
        ... }

        Full content:

        >>> content = {
        ...     'concepts': ["fashion"],
        ...     'certainty': 0.7, # or 'distance' instead
        ...     'moveAwayFrom': {
        ...         'concepts': ["finance"],
        ...         'force': 0.45
        ...     },
        ...     'moveTo': {
        ...         'concepts': ["haute couture"],
        ...         'force': 0.85
        ...     },
        ...     'autocorrect': True
        ... }

        Partial content:

        >>> content = {
        ...     'concepts': ["fashion"],
        ...     'certainty': 0.7, # or 'distance' instead
        ...     'moveTo': {
        ...         'concepts': ["haute couture"],
        ...         'force': 0.85
        ...     }
        ... }

        Minimal content:

        >>> content = {
        ...     'concepts': "fashion"
        ... }

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            Updated AggregateBuilder.

        Raises
        ------
        AttributeError
            If another 'near' filter was already set.
        #Cannot use multiple 'near' filters.T)r$   AttributeErrorr   r#   r@   s     r)   with_near_textzAggregateBuilder.with_near_text   s4    V ::! !FGGg&
 r*   c                 b    | j                   t        d      t        |      | _         d| _        | S )a  
        Set `nearVector` filter.

        Parameters
        ----------
        content : dict
            The content of the `nearVector` filter to set. See examples below.

        Examples
        --------
        Content full prototype:

        >>> content = {
        ...     'vector' : <list of float>,
        ...     # certainty ONLY with `cosine` distance specified in the schema
        ...     'certainty': <float>, # Optional, either 'certainty' OR 'distance'
        ...     'distance': <float>, # Optional, either 'certainty' OR 'distance'
        ... }

        NOTE: Supported types for 'vector' are `list`, 'numpy.ndarray`, `torch.Tensor`
                and `tf.Tensor`.

        Full content:

        >>> content = {
        ...     'vector' : [.1, .2, .3, .5],
        ...     'certainty': 0.75, # or 'distance' instead
        ... }

        Minimal content:

        >>> content = {
        ...     'vector' : [.1, .2, .3, .5]
        ... }

        Or

        >>> content = {
        ...     'vector' : torch.tensor([.1, .2, .3, .5])
        ... }

        Or

        >>> content = {
        ...     'vector' : torch.tensor([[.1, .2, .3, .5]]) # it is going to be squeezed.
        ... }

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            Updated AggregateBuilder.

        Raises
        ------
        AttributeError
            If another 'near' filter was already set.
        rF   T)r$   rG   r   r#   r@   s     r)   with_near_vectorz!AggregateBuilder.with_near_vector:  s4    v ::! !FGG(
 r*   c                     | j                   j                  dk\  }| j                  t        d      t	        ||      | _        d| _        | S )a  
        Set `nearObject` filter.

        Parameters
        ----------
        content : dict
            The content of the `nearObject` filter to set. See examples below.

        Examples
        --------
        Content prototype:

        >>> content = {
        ...     'id': <str>, # OR 'beacon'
        ...     'beacon': <str>, # OR 'id'
        ...     # certainty ONLY with `cosine` distance specified in the schema
        ...     'certainty': <float>, # Optional, either 'certainty' OR 'distance'
        ...     'distance': <float>, # Optional, either 'certainty' OR 'distance'
        ... }

        >>> {
        ...     'id': "e5dc4a4c-ef0f-3aed-89a3-a73435c6bbcf",
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> # alternatively
        >>> {
        ...     'beacon': "weaviate://localhost/Book/e5dc4a4c-ef0f-3aed-89a3-a73435c6bbcf"
        ...     'certainty': 0.7 # or 'distance' instead
        ... }

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            Updated AggregateBuilder.

        Raises
        ------
        AttributeError
            If another 'near' filter was already set.
        z1.14rF   T)_connectionserver_versionr$   rG   r   r#   )r'   r>   is_server_version_14s      r)   with_near_objectz!AggregateBuilder.with_near_object{  sN    T  $//>>&H::! !FGG)=>
 r*   encodec                     t         j                  | _        | j                  t	        d      |rt        |d         |d<   t        |      | _        d| _        | S )a  
        Set `nearImage` filter.

        Parameters
        ----------
        content : dict
            The content of the `nearImage` filter to set. See examples below.
        encode : bool, optional
            Whether to encode the `content["image"]` to base64 and convert to string. If True, the
            `content["image"]` can be an image path or a file opened in binary read mode. If False,
            the `content["image"]` MUST be a base64 encoded string (NOT bytes, i.e. NOT binary
            string that looks like this: b'BASE64ENCODED' but simple 'BASE64ENCODED').
            By default True.

        Examples
        --------
        Content prototype:

        >>> content = {
        ...     'image': <str or binary read file>,
        ...     # certainty ONLY with `cosine` distance specified in the schema
        ...     'certainty': <float>, # Optional, either 'certainty' OR 'distance'
        ...     'distance': <float>, # Optional, either 'certainty' OR 'distance'
        ... }

        >>> {
        ...     'image': "e5dc4a4c-ef0f-3aed-89a3-a73435c6bbcf",
        ...     'certainty': 0.7 # or 'distance'
        ... }

        With `encoded` True:

        >>> content = {
        ...     'image': "my_image_path.png",
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Image')\
                .with_fields('description')\
        ...     .with_near_image(content, encode=True) # <- encode MUST be set to True

        OR

        >>> my_image_file = open("my_image_path.png", "br")
        >>> content = {
        ...     'image': my_image_file,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Image')\
                .with_fields('description')\
        ...     .with_near_image(content, encode=True) # <- encode MUST be set to True
        >>> my_image_file.close()

        With `encoded` False:

        >>> from weaviate.util import image_encoder_b64, image_decoder_b64
        >>> encoded_image = image_encoder_b64("my_image_path.png")
        >>> content = {
        ...     'image': encoded_image,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Image')\
                .with_fields('description')\
        ...     .with_near_image(content, encode=False) # <- encode MUST be set to False

        OR

        >>> from weaviate.util import image_encoder_b64, image_decoder_b64
        >>> with open("my_image_path.png", "br") as my_image_file:
        ...     encoded_image = image_encoder_b64(my_image_file)
        >>> content = {
        ...     'image': encoded_image,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Image')\
                .with_fields('description')\
        ...     .with_near_image(content, encode=False) # <- encode MUST be set to False

        Encode Image yourself:

        >>> import base64
        >>> with open("my_image_path.png", "br") as my_image_file:
        ...     encoded_image = base64.b64encode(my_image_file.read()).decode("utf-8")
        >>> content = {
        ...     'image': encoded_image,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Image')\
                .with_fields('description')\
        ...     .with_near_image(content, encode=False) # <- encode MUST be set to False

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            The updated AggregateBuilder.

        Raises
        ------
        AttributeError
            If another 'near' filter was already set.
        QCannot use multiple 'near' filters, or a 'near' filter along with a 'ask' filter!imageT)r   IMAGE_media_typer$   rG   r   r   r#   r'   r>   rP   s      r)   with_near_imagez AggregateBuilder.with_near_image  s_    J %??::! (  /0@AGGw'
 r*   c                    t         j                  | _        | j                  t	        d      |r9t        || j                  j                           || j                  j                  <   t        |      | _        d| _        | S )a~  
        Set `nearAudio` filter.

        Parameters
        ----------
        content : dict
            The content of the `nearAudio` filter to set. See examples below.
        encode : bool, optional
            Whether to encode the `content["audio"]` to base64 and convert to string. If True, the
            `content["audio"]` can be an audio path or a file opened in binary read mode. If False,
            the `content["audio"]` MUST be a base64 encoded string (NOT bytes, i.e. NOT binary
            string that looks like this: b'BASE64ENCODED' but simple 'BASE64ENCODED').
            By default True.

        Examples
        --------
        Content prototype:

        >>> content = {
        ...     'audio': <str or binary read file>,
        ...     # certainty ONLY with `cosine` distance specified in the schema
        ...     'certainty': <float>, # Optional, either 'certainty' OR 'distance'
        ...     'distance': <float>, # Optional, either 'certainty' OR 'distance'
        ... }

        >>> {
        ...     'audio': "e5dc4a4c-ef0f-3aed-89a3-a73435c6bbcf",
        ...     'certainty': 0.7 # or 'distance'
        ... }

        With `encoded` True:

        >>> content = {
        ...     'audio': "my_audio_path.wav",
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Audio')\
                .with_fields('description')\
        ...     .with_near_audio(content, encode=True) # <- encode MUST be set to True

        OR

        >>> my_audio_file = open("my_audio_path.wav", "br")
        >>> content = {
        ...     'audio': my_audio_file,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Audio')\
                .with_fields('description')\
        ...     .with_near_audio(content, encode=True) # <- encode MUST be set to True
        >>> my_audio_file.close()

        With `encoded` False:

        >>> from weaviate.util import file_encoder_b64
        >>> encoded_audio = file_encoder_b64("my_audio_path.wav")
        >>> content = {
        ...     'audio': encoded_audio,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Audio')\
                .with_fields('description')\
        ...     .with_near_audio(content, encode=False) # <- encode MUST be set to False

        OR

        >>> from weaviate.util import file_encoder_b64
        >>> with open("my_audio_path.wav", "br") as my_audio_file:
        ...     encoded_audio = file_encoder_b64(my_audio_file)
        >>> content = {
        ...     'audio': encoded_audio,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Audio')\
                .with_fields('description')\
        ...     .with_near_audio(content, encode=False) # <- encode MUST be set to False

        Encode Audio yourself:

        >>> import base64
        >>> with open("my_audio_path.wav", "br") as my_audio_file:
        ...     encoded_audio = base64.b64encode(my_audio_file.read()).decode("utf-8")
        >>> content = {
        ...     'audio': encoded_audio,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Audio')\
                .with_fields('description')\
        ...     .with_near_audio(content, encode=False) # <- encode MUST be set to False

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            The updated AggregateBuilder.

        Raises
        ------
        AttributeError
            If another 'near' filter was already set.
        rR   T)	r   AUDIOrU   r$   rG   r   valuer   r#   rV   s      r)   with_near_audioz AggregateBuilder.with_near_audio  w    L %??::! (  .>wtGWGWG]G]?^._GD$$**+w'
 r*   c                    t         j                  | _        | j                  t	        d      |r9t        || j                  j                           || j                  j                  <   t        |      | _        d| _        | S )a  
        Set `nearVideo` filter.

        Parameters
        ----------
        content : dict
            The content of the `nearVideo` filter to set. See examples below.
        encode : bool, optional
            Whether to encode the `content["video"]` to base64 and convert to string. If True, the
            `content["video"]` can be an video path or a file opened in binary read mode. If False,
            the `content["video"]` MUST be a base64 encoded string (NOT bytes, i.e. NOT binary
            string that looks like this: b'BASE64ENCODED' but simple 'BASE64ENCODED').
            By default True.

        Examples
        --------
        Content prototype:

        >>> content = {
        ...     'video': <str or binary read file>,
        ...     # certainty ONLY with `cosine` distance specified in the schema
        ...     'certainty': <float>, # Optional, either 'certainty' OR 'distance'
        ...     'distance': <float>, # Optional, either 'certainty' OR 'distance'
        ... }

        >>> {
        ...     'video': "e5dc4a4c-ef0f-3aed-89a3-a73435c6bbcf",
        ...     'certainty': 0.7 # or 'distance'
        ... }

        With `encoded` True:

        >>> content = {
        ...     'video': "my_video_path.avi",
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Video')\
                .with_fields('description')\
        ...     .with_near_video(content, encode=True) # <- encode MUST be set to True

        OR

        >>> my_video_file = open("my_video_path.avi", "br")
        >>> content = {
        ...     'video': my_video_file,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Video')\
                .with_fields('description')\
        ...     .with_near_video(content, encode=True) # <- encode MUST be set to True
        >>> my_video_file.close()

        With `encoded` False:

        >>> from weaviate.util import file_encoder_b64
        >>> encoded_video = file_encoder_b64("my_video_path.avi")
        >>> content = {
        ...     'video': encoded_video,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Video')\
                .with_fields('description')\
        ...     .with_near_video(content, encode=False) # <- encode MUST be set to False

        OR

        >>> from weaviate.util import file_encoder_b64, video_decoder_b64
        >>> with open("my_video_path.avi", "br") as my_video_file:
        ...     encoded_video = file_encoder_b64(my_video_file)
        >>> content = {
        ...     'video': encoded_video,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Video')\
                .with_fields('description')\
        ...     .with_near_video(content, encode=False) # <- encode MUST be set to False

        Encode Video yourself:

        >>> import base64
        >>> with open("my_video_path.avi", "br") as my_video_file:
        ...     encoded_video = base64.b64encode(my_video_file.read()).decode("utf-8")
        >>> content = {
        ...     'video': encoded_video,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Video')\
                .with_fields('description')\
        ...     .with_near_video(content, encode=False) # <- encode MUST be set to False

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            The updated AggregateBuilder.

        Raises
        ------
        AttributeError
            If another 'near' filter was already set.
        rR   T)	r   VIDEOrU   r$   rG   r   rZ   r   r#   rV   s      r)   with_near_videoz AggregateBuilder.with_near_video  r\   r*   c                    t         j                  | _        | j                  t	        d      |r9t        || j                  j                           || j                  j                  <   t        |      | _        d| _        | S )a~  
        Set `nearDepth` filter.

        Parameters
        ----------
        content : dict
            The content of the `nearDepth` filter to set. See examples below.
        encode : bool, optional
            Whether to encode the `content["depth"]` to base64 and convert to string. If True, the
            `content["depth"]` can be an depth path or a file opened in binary read mode. If False,
            the `content["depth"]` MUST be a base64 encoded string (NOT bytes, i.e. NOT binary
            string that looks like this: b'BASE64ENCODED' but simple 'BASE64ENCODED').
            By default True.

        Examples
        --------
        Content prototype:

        >>> content = {
        ...     'depth': <str or binary read file>,
        ...     # certainty ONLY with `cosine` distance specified in the schema
        ...     'certainty': <float>, # Optional, either 'certainty' OR 'distance'
        ...     'distance': <float>, # Optional, either 'certainty' OR 'distance'
        ... }

        >>> {
        ...     'depth': "e5dc4a4c-ef0f-3aed-89a3-a73435c6bbcf",
        ...     'certainty': 0.7 # or 'distance'
        ... }

        With `encoded` True:

        >>> content = {
        ...     'depth': "my_depth_path.png",
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Depth')\
                .with_fields('description')\
        ...     .with_near_depth(content, encode=True) # <- encode MUST be set to True

        OR

        >>> my_depth_file = open("my_depth_path.png", "br")
        >>> content = {
        ...     'depth': my_depth_file,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Depth')\
                .with_fields('description')\
        ...     .with_near_depth(content, encode=True) # <- encode MUST be set to True
        >>> my_depth_file.close()

        With `encoded` False:

        >>> from weaviate.util import file_encoder_b64
        >>> encoded_depth = file_encoder_b64("my_depth_path.png")
        >>> content = {
        ...     'depth': encoded_depth,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Depth')\
                .with_fields('description')\
        ...     .with_near_depth(content, encode=False) # <- encode MUST be set to False

        OR

        >>> from weaviate.util import file_encoder_b64
        >>> with open("my_depth_path.png", "br") as my_depth_file:
        ...     encoded_depth = file_encoder_b64(my_depth_file)
        >>> content = {
        ...     'depth': encoded_depth,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Depth')\
                .with_fields('description')\
        ...     .with_near_depth(content, encode=False) # <- encode MUST be set to False

        Encode Depth yourself:

        >>> import base64
        >>> with open("my_depth_path.png", "br") as my_depth_file:
        ...     encoded_depth = base64.b64encode(my_depth_file.read()).decode("utf-8")
        >>> content = {
        ...     'depth': encoded_depth,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Depth')\
                .with_fields('description')\
        ...     .with_near_depth(content, encode=False) # <- encode MUST be set to False

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            The updated AggregateBuilder.

        Raises
        ------
        AttributeError
            If another 'near' filter was already set.
        rR   T)	r   DEPTHrU   r$   rG   r   rZ   r   r#   rV   s      r)   with_near_depthz AggregateBuilder.with_near_depth  r\   r*   c                    t         j                  | _        | j                  t	        d      |r9t        || j                  j                           || j                  j                  <   t        |      | _        d| _        | S )a  
        Set `nearThermal` filter.

        Parameters
        ----------
        content : dict
            The content of the `nearThermal` filter to set. See examples below.
        encode : bool, optional
            Whether to encode the `content["thermal"]` to base64 and convert to string. If True, the
            `content["thermal"]` can be an thermal path or a file opened in binary read mode. If False,
            the `content["thermal"]` MUST be a base64 encoded string (NOT bytes, i.e. NOT binary
            string that looks like this: b'BASE64ENCODED' but simple 'BASE64ENCODED').
            By default True.

        Examples
        --------
        Content prototype:

        >>> content = {
        ...     'thermal': <str or binary read file>,
        ...     # certainty ONLY with `cosine` distance specified in the schema
        ...     'certainty': <float>, # Optional, either 'certainty' OR 'distance'
        ...     'distance': <float>, # Optional, either 'certainty' OR 'distance'
        ... }

        >>> {
        ...     'thermal': "e5dc4a4c-ef0f-3aed-89a3-a73435c6bbcf",
        ...     'certainty': 0.7 # or 'distance'
        ... }

        With `encoded` True:

        >>> content = {
        ...     'thermal': "my_thermal_path.png",
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.get('Thermal', 'description')\
        ...     .with_near_thermal(content, encode=True) # <- encode MUST be set to True

        OR

        >>> my_thermal_file = open("my_thermal_path.png", "br")
        >>> content = {
        ...     'thermal': my_thermal_file,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Thermal')\
        ...     .with_fields('description')\
        ...     .with_near_thermal(content, encode=True) # <- encode MUST be set to True
        >>> my_thermal_file.close()

        With `encoded` False:

        >>> from weaviate.util import file_encoder_b64
        >>> encoded_thermal = file_encoder_b64("my_thermal_path.png")
        >>> content = {
        ...     'thermal': encoded_thermal,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Thermal')\
        ...     .with_fields('description')\
        ...     .with_near_thermal(content, encode=False) # <- encode MUST be set to False

        OR

        >>> from weaviate.util import file_encoder_b64
        >>> with open("my_thermal_path.png", "br") as my_thermal_file:
        ...     encoded_thermal = file_encoder_b64(my_thermal_file)
        >>> content = {
        ...     'thermal': encoded_thermal,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Thermal')\
        ...     .with_fields('description')\
        ...     .with_near_thermal(content, encode=False) # <- encode MUST be set to False

        Encode Thermal yourself:

        >>> import base64
        >>> with open("my_thermal_path.png", "br") as my_thermal_file:
        ...     encoded_thermal = base64.b64encode(my_thermal_file.read()).decode("utf-8")
        >>> content = {
        ...     'thermal': encoded_thermal,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('Thermal')\
        ...     .with_fields('description')\
        ...     .with_near_thermal(content, encode=False) # <- encode MUST be set to False

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            The updated AggregateBuilder.

        Raises
        ------
        AttributeError
            If another 'near' filter was already set.
        rR   T)	r   THERMALrU   r$   rG   r   rZ   r   r#   rV   s      r)   with_near_thermalz"AggregateBuilder.with_near_thermalt  sy    J %,,::! (  .>wtGWGWG]G]?^._GD$$**+ )
 r*   c                    t         j                  | _        | j                  t	        d      |r9t        || j                  j                           || j                  j                  <   t        |      | _        d| _        | S )a  
        Set `nearIMU` filter.

        Parameters
        ----------
        content : dict
            The content of the `nearIMU` filter to set. See examples below.
        encode : bool, optional
            Whether to encode the `content["thermal"]` to base64 and convert to string. If True, the
            `content["thermal"]` can be an thermal path or a file opened in binary read mode. If False,
            the `content["thermal"]` MUST be a base64 encoded string (NOT bytes, i.e. NOT binary
            string that looks like this: b'BASE64ENCODED' but simple 'BASE64ENCODED').
            By default True.

        Examples
        --------
        Content prototype:

        >>> content = {
        ...     'thermal': <str or binary read file>,
        ...     # certainty ONLY with `cosine` distance specified in the schema
        ...     'certainty': <float>, # Optional, either 'certainty' OR 'distance'
        ...     'distance': <float>, # Optional, either 'certainty' OR 'distance'
        ... }

        >>> {
        ...     'thermal': "e5dc4a4c-ef0f-3aed-89a3-a73435c6bbcf",
        ...     'certainty': 0.7 # or 'distance'
        ... }

        With `encoded` True:

        >>> content = {
        ...     'thermal': "my_thermal_path.png",
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('IMU')\
        ...     .with_fields('description')\
        ...     .with_near_thermal(content, encode=True) # <- encode MUST be set to True

        OR

        >>> my_thermal_file = open("my_thermal_path.png", "br")
        >>> content = {
        ...     'thermal': my_thermal_file,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('IMU')\
        ...     .with_fields('description')\
        ...     .with_near_thermal(content, encode=True) # <- encode MUST be set to True
        >>> my_thermal_file.close()

        With `encoded` False:

        >>> from weaviate.util import file_encoder_b64
        >>> encoded_thermal = file_encoder_b64("my_thermal_path.png")
        >>> content = {
        ...     'thermal': encoded_thermal,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('IMU')\
        ...     .with_fields('description')\
        ...     .with_near_thermal(content, encode=False) # <- encode MUST be set to False

        OR

        >>> from weaviate.util import file_encoder_b64
        >>> with open("my_thermal_path.png", "br") as my_thermal_file:
        ...     encoded_thermal = file_encoder_b64(my_thermal_file)
        >>> content = {
        ...     'thermal': encoded_thermal,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('IMU')\
        ...     .with_fields('description')\
        ...     .with_near_thermal(content, encode=False) # <- encode MUST be set to False

        Encode IMU yourself:

        >>> import base64
        >>> with open("my_thermal_path.png", "br") as my_thermal_file:
        ...     encoded_thermal = base64.b64encode(my_thermal_file.read()).decode("utf-8")
        >>> content = {
        ...     'thermal': encoded_thermal,
        ...     'certainty': 0.7 # or 'distance' instead
        ... }
        >>> query = client.query.aggregate('IMU')\
        ...     .with_fields('description')\
        ...     .with_near_thermal(content, encode=False) # <- encode MUST be set to False

        Returns
        -------
        weaviate.gql.aggregate.AggregateBuilder
            The updated AggregateBuilder.

        Raises
        ------
        AttributeError
            If another 'near' filter was already set.
        rR   T)	r   IMUrU   r$   rG   r   rZ   r   r#   rV   s      r)   with_near_imuzAggregateBuilder.with_near_imu  sw    L %==::! (  .>wtGWGWG]G]?^._GD$$**+W%
 r*   c                 Z   d| j                    }| j                  r|dz  }| j                  |t        | j                        z  }| j                  %|dt        j                  | j                         z  }| j                  |t        | j                        z  }| j                  r|d| j                   z  }| j                  |d| j                   dz  }| j                  |d| j                   z  }|dz  }|d	z  }| j                  r|d
z  }| j                  D ]  }||z  }	 |dz  }|S )z
        Build the query and return the string.

        Returns
        -------
        str
            The GraphQL query as a string.
        z{Aggregate{(z	groupBy: zobjectLimit: z	tenant: ""zlimit: ){zmeta{count}z}}})r   r#   r!   r/   r"   jsondumpsr$   r   r%   r&   r   r    )r'   queryr:   s      r)   buildzAggregateBuilder.buildW  sE      0 012 SLE{{&T[[))((49TZZ0I0I%J$KLLzz%TZZ(!!=););(<==||'9T\\N!44{{&74;;-00SLE 	  ]"E\\ 	EUNE	 	r*   )r,   r   )T)__name__
__module____qualname____doc__r/   r   r   r1   r3   intr7   r9   r=   dictrA   r   rD   rH   rJ   rO   boolrW   r[   r_   rb   re   rh   rq   __classcell__)r(   s   @r)   r   r      s   *3 *J *0# *< s /A & (: $ ); &I$ I+= IVtCy =O ,Od O/A Ob? ?1C ?B0 01C 0dot oT oEW obpt pT pEW pdpt pT pEW pdpt pT pEW pdo ot oGY obpT p4 pCU pd(s (r*   r   )ru   rn   typingr   r   weaviate.connectr   weaviate.utilr   r   filterr	   r
   r   r   r   r   r   r   r   r   r   r   r   r    r*   r)   <module>r      s<     ! '   "bw br*   