
    Ng                      d Z ddlmZ ddlZddlZddlZddlZddl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mZmZmZmZmZmZmZmZmZmZmZmZ dd	l m!Z!m"Z"m#Z#m$Z$m%Z%m&Z& dd
l'm(Z( ddl)m*Z* ddl+m,Z, ddl-m.Z/ ddl0m1Z1m2Z2 ddl3m4Z4 	 ddl+m5Z5 n# e6$ r	 ddl7m5Z5 Y nw xY wddl8m9Z9m:Z: ddl;m<Z<m=Z= ddl>m?Z? ddl@mAZAmBZBmCZC ddlDmEZE ddlFmGZG ddlHmIZImJZJ ddlKmLZL ddlMm.ZN ddlMmOZO ddlPmQZQ ddlPmRZS ddlTmUZV ddlWmXZX  ejY        eZ          Z[erddl\Z\ddl]Z]ddl^m_Z_m`Z` ddlam,Zb dwd"Zcdxd%Zddyd'Zedxd(Zfdzd+Zg G d, d-e=          Zh e5            Zi G d. d/ei          Zj G d0 d1e=          Zk G d2 d3ek          Zl G d4 d5e=          Zm G d6 d7e=e
          Zn G d8 d9en          Zo G d: d;en          Zp G d< d=e=          Zq G d> d?e=          Zrd{dDZsd|dGZt G dH dIe=          ZudJZvdZw G dK dLe=          ZxdMZydNZzdOZ{dZ|dPZ} G dQ dRe=          Z~ G dS dTei          Z G dU dVe=          ZdWZ e9dXdYdZ[           G d\ d]e=                      ZdNZd^ZdPZd_gZ G d` da          Zd}ddZd~ddkZ e9dXdYdl[           G dm dne=                      Z G do dpe=          Z G dq dre=          Z G ds dte=          Z G du dve=          ZdS )a<  
.. warning::
  Beta Feature!

**Cache** provides an optional caching layer for LLMs.

Cache is useful for two reasons:

- It can save you money by reducing the number of API calls you make to the LLM
  provider if you're often requesting the same completion multiple times.
- It can speed up your application by reducing the number of API calls you make
  to the LLM provider.

Cache directly competes with Memory. See documentation for Pros and Cons.

**Class hierarchy:**

.. code-block::

    BaseCache --> <name>Cache  # Examples: InMemoryCache, RedisCache, GPTCache
    )annotationsN)ABC)	timedelta)Enum)	lru_cachewraps)TYPE_CHECKINGAny	AwaitableCallableDict	GeneratorListOptionalSequenceTupleTypeUnioncast)ColumnIntegerStringcreate_enginedeleteselect)Row)Engine)Session)	SetupMode)CosmosDBSimilarityTypeCosmosDBVectorSearchType)DistanceStrategy)declarative_base)
deprecatedwarn_deprecated)RETURN_VAL_TYPE	BaseCache)
Embeddings)LLMaget_promptsget_promptsdumpsloads)ChatGeneration
Generation)get_from_env)_AstraDBCollectionEnvironment)AzureCosmosDBVectorSearch)OpenSearchVectorSearchRedis)SingleStoreDB)AstraDBAsyncAstraDB_inputstrreturnc                r    t          j        |                                                                           S )z%Use a deterministic hashing approach.hashlibmd5encode	hexdigest)r;   s    U/var/www/html/ai-engine/env/lib/python3.11/site-packages/langchain_community/cache.py_hashrE   c   s&    ;v}}''11333    generationsr&   c                >    t          j        d | D                       S )a  Dump generations to json.

    Args:
        generations (RETURN_VAL_TYPE): A list of language model generations.

    Returns:
        str: Json representing a list of generations.

    Warning: would not work well with arbitrary subclasses of `Generation`
    c                6    g | ]}|                                 S  )dict).0
generations     rD   
<listcomp>z-_dump_generations_to_json.<locals>.<listcomp>s   s"    GGGZz((GGGrF   jsonr-   rG   s    rD   _dump_generations_to_jsonrR   h   s#     :GG;GGGHHHrF   generations_jsonc                    	 t          j        |           }d |D             S # t           j        $ r t          d|            w xY w)a`  Load generations from json.

    Args:
        generations_json (str): A string of json representing a list of generations.

    Raises:
        ValueError: Could not decode json string to list of generations.

    Returns:
        RETURN_VAL_TYPE: A list of generations.

    Warning: would not work well with arbitrary subclasses of `Generation`
    c                &    g | ]}t          d i |S rJ   r1   rL   generation_dicts     rD   rN   z/_load_generations_from_json.<locals>.<listcomp>   s&    MMM/
--_--MMMrF   z.Could not decode json to list of generations: )rP   r/   JSONDecodeError
ValueError)rS   resultss     rD   _load_generations_from_jsonr]   v   sg    
*-..MMWMMMM 
 
 
O=MOO
 
 	

s	   " "Ac                >    t          j        d | D                       S )a  
    Serialization for generic RETURN_VAL_TYPE, i.e. sequence of `Generation`

    Args:
        generations (RETURN_VAL_TYPE): A list of language model generations.

    Returns:
        str: a single string representing a list of generations.

    This function (+ its counterpart `_loads_generations`) rely on
    the dumps/loads pair with Reviver, so are able to deal
    with all subclasses of Generation.

    Each item in the list can be `dumps`ed to a string,
    then we make the whole list of strings into a json-dumped.
    c                ,    g | ]}t          |          S rJ   r,   )rL   _items     rD   rN   z&_dumps_generations.<locals>.<listcomp>   s    ===uU||===rF   rO   rQ   s    rD   _dumps_generationsra      s#    " :=====>>>rF   generations_strUnion[RETURN_VAL_TYPE, None]c                t   	 d t          j        |           D             }|S # t           j        t          f$ r Y nw xY w	 t          j        |           }d |D             }t                              d|  d           |S # t           j        t          f$ r" t                              d|  d           Y dS w xY w)a  
    Deserialization of a string into a generic RETURN_VAL_TYPE
    (i.e. a sequence of `Generation`).

    See `_dumps_generations`, the inverse of this function.

    Args:
        generations_str (str): A string representing a list of generations.

    Compatible with the legacy cache-blob format
    Does not raise exceptions for malformed entries, just logs a warning
    and returns none: the caller should be prepared for such a cache miss.

    Returns:
        RETURN_VAL_TYPE: A list of generations.
    c                ,    g | ]}t          |          S rJ   r.   )rL   	_item_strs     rD   rN   z&_loads_generations.<locals>.<listcomp>   s     UUUIuY''UUUrF   c                &    g | ]}t          d i |S rV   rW   rX   s     rD   rN   z&_loads_generations.<locals>.<listcomp>   s&    VVVz44O44VVVrF   z.Legacy 'Generation' cached blob encountered: ''z/Malformed/unparsable cached blob encountered: 'N)rP   r/   rZ   	TypeErrorloggerwarning)rb   rG   	gen_dictss      rD   _loads_generationsrm      s    "UUO9T9TUUU ),   J//	VVIVVVO_OOO	
 	
 	
  ),   PoPPP	
 	
 	
 tt	s   " ;;?A? ?4B76B7c                  J    e Zd ZdZddZdd	ZddZddZddZddZ	ddZ
dS )InMemoryCachez#Cache that stores things in memory.r=   Nonec                    i | _         dS )zInitialize with empty cache.N_cacheselfs    rD   __init__zInMemoryCache.__init__   s    >@rF   promptr<   
llm_stringOptional[RETURN_VAL_TYPE]c                <    | j                             ||fd          S 'Look up based on prompt and llm_string.N)rs   getru   rw   rx   s      rD   lookupzInMemoryCache.lookup   s    {
3T:::rF   
return_valr&   c                    || j         ||f<   dS ,Update cache based on prompt and llm_string.Nrr   ru   rw   rx   r   s       rD   updatezInMemoryCache.update   s    ,6VZ()))rF   kwargsr
   c                    i | _         dS Clear cache.Nrr   ru   r   s     rD   clearzInMemoryCache.clear   s    rF   c                2   K   |                      ||          S )r|   )r   r~   s      rD   alookupzInMemoryCache.alookup   s      {{6:...rF   c                8   K   |                      |||           dS r   )r   r   s       rD   aupdatezInMemoryCache.aupdate   s$       	FJ
33333rF   c                2   K   |                                   dS r   )r   r   s     rD   aclearzInMemoryCache.aclear   s      

rF   N)r=   rp   rw   r<   rx   r<   r=   ry   rw   r<   rx   r<   r   r&   r=   rp   r   r
   r=   rp   )__name__
__module____qualname____doc__rv   r   r   r   r   r   r   rJ   rF   rD   ro   ro      s        --A A A A; ; ; ;7 7 7 7   / / / /4 4 4 4     rF   ro   c                  z    e Zd ZdZdZ eed          Z eed          Z ee	d          Z
 ee          ZdS )FullLLMCache2SQLite table for full LLM Cache (all generations).full_llm_cacheTprimary_keyN)r   r   r   r   __tablename__r   r   rw   llmr   idxresponserJ   rF   rD   r   r      sb        <<$MVF---F
&T
*
*
*C
&d
+
+
+Cvf~~HHHrF   r   c                  6    e Zd ZdZefddZddZddZddZdS )SQLAlchemyCache'Cache that uses SQAlchemy as a backend.enginer   cache_schemaType[FullLLMCache]c                j    || _         || _        | j        j                            | j                    dS z"Initialize by creating all tables.Nr   r   metadata
create_allru   r   r   s      rD   rv   zSQLAlchemyCache.__init__   s3    ("--dk:::::rF   rw   r<   rx   r=   ry   c                X   t          | j        j                                      | j        j        |k                                  | j        j        |k                                  | j        j                  }t          | j	                  5 }|
                    |                                          }|r[	 d |D             cddd           S # t          $ r5 t                              d           d |D             cY cddd           S w xY w	 ddd           n# 1 swxY w Y   dS )r|   c                8    g | ]}t          |d                    S r   r.   rL   rows     rD   rN   z*SQLAlchemyCache.lookup.<locals>.<listcomp>  s"    :::cE#a&MM:::rF   NRetrieving a cache value that could not be deserialized properly. This is likely due to the cache being in an older format. Please recreate your cache to avoid this error.c                :    g | ]}t          |d                    S )r   textrW   r   s     rD   rN   z*SQLAlchemyCache.lookup.<locals>.<listcomp>  s'    DDDJCF333DDDrF   )r   r   r   whererw   r   order_byr   r   r   executefetchall	Exceptionrj   rk   )ru   rw   rx   stmtsessionrowss         rD   r   zSQLAlchemyCache.lookup   s    4$-..U4$+v566U4$(J677Xd'+,,	 	 T[!! 	EW??4((1133D EE::T:::		E 	E 	E 	E 	E 	E 	E 	E
 ! 	E 	E 	ENN!   EDtDDDDD	E 	E 	E 	E 	E 	E 	E 	E
	EE	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E ts0   *D8C0D DDDD#&D#r   r&   rp   c                .     fdt          |          D             }t           j                  5 }|                                5  |D ]}|                    |           	 ddd           n# 1 swxY w Y   ddd           dS # 1 swxY w Y   dS )&Update based on prompt and llm_string.c           	     b    g | ]+\  }}                     t          |          |           ,S ))rw   r   r   r   )r   r-   )rL   igenrx   rw   ru   s      rD   rN   z*SQLAlchemyCache.update.<locals>.<listcomp>  sK     
 
 
3 VeCjjVWXX
 
 
rF   N)	enumerater   r   beginmerge)ru   rw   rx   r   itemsr   items   ```    rD   r   zSQLAlchemyCache.update  s=   
 
 
 
 
 
#J//
 
 
 T[!! 	$Wgmmoo 	$ 	$ $ $d####$	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$s5   B

A2&B
2A6	6B
9A6	:B

BBr   r
   c                    t          | j                  5 }|                    | j                                                   |                                 ddd           dS # 1 swxY w Y   dS r   )r   r   queryr   r   commitru   r   r   s      rD   r   zSQLAlchemyCache.clear#  s    T[!! 	WMM$+,,33555NN	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   AA##A'*A'N)r   r   r   r   r   r   r   )	r   r   r   r   r   rv   r   r   r   rJ   rF   rD   r   r      sr        11JV ; ; ; ; ;   2$ $ $ $     rF   r   c                  &     e Zd ZdZdd fdZ xZS )SQLiteCachez$Cache that uses SQLite as a backend..langchain.dbdatabase_pathr<   c                n    t          d|           }t                                          |           dS )z1Initialize by creating the engine and all tables.z
sqlite:///N)r   superrv   )ru   r   r   	__class__s      rD   rv   zSQLiteCache.__init__-  s7    ;M;;<<     rF   )r   )r   r<   )r   r   r   r   rv   __classcell__)r   s   @rD   r   r   *  sH        ..! ! ! ! ! ! ! ! ! ! !rF   r   c                  @    e Zd ZdZddddZddZddZddZddZdS )UpstashRedisCachez+Cache that uses Upstash Redis as a backend.Nttlredis_r
   r   Optional[int]c                   	 ddl m} n# t          $ r t          d          w xY wt          ||          st	          d          || _        || _        dS )ag  
        Initialize an instance of UpstashRedisCache.

        This method initializes an object with Upstash Redis caching capabilities.
        It takes a `redis_` parameter, which should be an instance of an Upstash Redis
        client class, allowing the object to interact with Upstash Redis
        server for caching purposes.

        Parameters:
            redis_: An instance of Upstash Redis client class
                (e.g., Redis) used for caching.
                This allows the object to communicate with
                Redis server for caching operations on.
            ttl (int, optional): Time-to-live (TTL) for cached items in seconds.
                If provided, it sets the time duration for how long cached
                items will remain valid. If not provided, cached items will not
                have an automatic expiration.
        r   r6   zbCould not import upstash_redis python package. Please install it with `pip install upstash_redis`.z$Please pass in Upstash Redis object.N)upstash_redisr7   ImportError
isinstancer[   redisr   ru   r   r   r7   s       rD   rv   zUpstashRedisCache.__init__6  s    &	+++++++ 	 	 	F  	
 &%(( 	ECDDD
   	 #rw   r<   rx   r=   c                &    t          ||z             S z&Compute key from prompt and llm_stringrE   r~   s      rD   _keyzUpstashRedisCache._keyU  s    Vj()))rF   ry   c                    g }| j                             |                     ||                    }|r=|                                D ](\  }}|                    t          |                     )|r|ndS )r|   r   N)r   hgetallr   r   appendr1   )ru   rw   rx   rG   r\   _r   s          rD   r   zUpstashRedisCache.lookupY  s~    *$$TYYvz%B%BCC 	:"==?? : :4"":4#8#8#89999)3{{t3rF   r   r&   rp   c                   |D ]b}t          |t                    st          dt          |                     t          |t                    rt          j        d            dS c|                     ||          }d t          |          D             }| j	        
                    ||           | j        "| j	                            || j                   dS dS )r   zBUpstashRedisCache supports caching of normal LLM generations, got zcNOTE: Generation has not been cached. UpstashRedisCache does not support caching ChatModel outputs.Nc                >    i | ]\  }}t          |          |j        S rJ   )r<   r   rL   r   rM   s      rD   
<dictcomp>z,UpstashRedisCache.update.<locals>.<dictcomp>t  s3     
 
 
*9#zCHHjo
 
 
rF   )keyvalues)r   r1   r[   typer0   warningswarnr   r   r   hsetr   expire)ru   rw   rx   r   r   r   mappings          rD   r   zUpstashRedisCache.updatec  s    	 	Cc:..  '99' '   #~.. :    ii
++
 
=Fz=R=R
 
 
 	
C0008Jc48,,,,,  rF   r   c                v    |                     dd          }|rd}nd}| j                            |           dS )zt
        Clear cache. If `asynchronous` is True, flush asynchronously.
        This flushes the *whole* db.
        asynchronousFASYNCSYNC)
flush_typeN)r}   r   flushdb)ru   r   r   s      rD   r   zUpstashRedisCache.clear|  sJ    
 zz.%88 	""LL!L
l33333rF   r   r
   r   r   rw   r<   rx   r<   r=   r<   r   r   r   )	r   r   r   r   rv   r   r   r   r   rJ   rF   rD   r   r   3  s        55<@      >* * * *4 4 4 4- - - -2
4 
4 
4 
4 
4 
4rF   r   c                  r    e Zd Zedd            Zedd	            Zedd            Ze	 ddd            ZdS )_RedisCacheBaserw   r<   rx   r=   c                &    t          | |z             S r   r   rw   rx   s     rD   r   z_RedisCacheBase._key  s     Vj()))rF   r   r&   rp   c                x    | D ]6}t          |t                    st          dt          |                     7d S )Nz@RedisCache only supports caching of normal LLM generations, got )r   r1   r[   r   )r   r   s     rD   _ensure_generation_typez'_RedisCacheBase._ensure_generation_type  s\     	 	Cc:..  '99' '  	 	rF   r\   dict[str | bytes, str | bytes]Optional[List[Generation]]c           	     P   g }| r|                                  D ]\  }}	 |                    t          t          t          |                               <# t
          $ r@ t                              d           |                    t          |                     Y w xY w|r|nd S )Nr   r   )	r   r   r/   r   r<   r   rj   rk   r1   )r\   rG   r   r   s       rD   _get_generationsz _RedisCacheBase._get_generations  s      	>"==?? > >4>&&uT#t__'='=>>>>  	> 	> 	>NN!    &&zt'<'<'<=====	> *3{{t3s   5AABBNr   piper
   r   r   c                    |                     | d t          |          D                        ||                    | |           d S d S )Nc                N    i | ]"\  }}t          |          t          |          #S rJ   )r<   r-   r   s      rD   r   zB_RedisCacheBase._configure_pipeline_for_update.<locals>.<dictcomp>  s9       0?ZC%
++  rF   )r   )r   r   r   )r   r	  r   r   s       rD   _configure_pipeline_for_updatez._RedisCacheBase._configure_pipeline_for_update  sn     			 CLZCXCX   	 	
 	
 	
 ?KKS!!!!! ?rF   r   )r   r&   r=   rp   )r\   r  r=   r  N)
r   r<   r	  r
   r   r&   r   r   r=   rp   )r   r   r   staticmethodr   r  r  r  rJ   rF   rD   r   r     s        * * * \*    \ 4 4 4 \4( OS
" 
" 
" 
" \
" 
" 
"rF   r   c                  8    e Zd ZdZddddZddZddZddZdS )
RedisCachezX
    Cache that uses Redis as a backend. Allows to use a sync `redis.Redis` client.
    Nr   r   r
   r   r   c                   	 ddl m} n# t          $ r t          d          w xY wt          ||          st	          d          || _         || _        dS )a`  
        Initialize an instance of RedisCache.

        This method initializes an object with Redis caching capabilities.
        It takes a `redis_` parameter, which should be an instance of a Redis
        client class (`redis.Redis`), allowing the object
        to interact with a Redis server for caching purposes.

        Parameters:
            redis_ (Any): An instance of a Redis client class
                (`redis.Redis`) to be used for caching.
                This allows the object to communicate with a
                Redis server for caching operations.
            ttl (int, optional): Time-to-live (TTL) for cached items in seconds.
                If provided, it sets the time duration for how long cached
                items will remain valid. If not provided, cached items will not
                have an automatic expiration.
        r   r6   zTCould not import `redis` python package. Please install it with `pip install redis`.z)Please pass a valid `redis.Redis` client.N)r   r7   r   r   r[   r   r   s       rD   rv   zRedisCache.__init__  s    &	####### 	 	 	>  	
 &%(( 	JHIII
r   rw   r<   rx   r=   ry   c                    	 | j                             |                     ||                    }|                     |          S # t          $ r(}t
                              d|            Y d}~dS d}~ww xY w)r|   zRedis lookup failed: Nr   r   r   r  r   rj   errorru   rw   rx   r\   es        rD   r   zRedisCache.lookup  s    	j((6:)F)FGGG((111 	 	 	LL44455544444	s   AA 
A7A22A7r   r&   rp   c                   |                      |           |                     ||          }	 | j                                        5 }|                     |||| j                   |                                 ddd           dS # 1 swxY w Y   dS # t          $ r(}t          	                    d|            Y d}~dS d}~ww xY w)r   NzRedis update failed: 
r  r   r   pipeliner  r   r   r   rj   r  ru   rw   rx   r   r   r	  r  s          rD   r   zRedisCache.update  s   $$Z000ii
++	6$$&& $33Cz48TTT                   	6 	6 	6LL444555555555	6s;   B 2B8B B		B B	B 
CB??Cr   c                    	 |                     dd          } | j        j        dd|i| dS # t          $ r(}t                              d|            Y d}~dS d}~ww xY w)=Clear cache. If `asynchronous` is True, flush asynchronously.r   FzRedis clear failed: NrJ   r}   r   r   r   rj   r  ru   r   r   r  s       rD   r   zRedisCache.clear  s    	5!::ne<<LDJCCLCFCCCCC 	5 	5 	5LL333444444444	5s   *. 
A AA r   r   r   r   r   r   r   r   rv   r   r   r   rJ   rF   rD   r  r    s~          =A      >   	6 	6 	6 	65 5 5 5 5 5rF   r  c                  P    e Zd ZdZddddZddZddZddZddZddZ	ddZ
dS )AsyncRedisCachezf
    Cache that uses Redis as a backend. Allows to use an
    async `redis.asyncio.Redis` client.
    Nr   r   r
   r   r   c                   	 ddl m} n# t          $ r t          d          w xY wt          ||          st	          d          || _        || _        dS )au  
        Initialize an instance of AsyncRedisCache.

        This method initializes an object with Redis caching capabilities.
        It takes a `redis_` parameter, which should be an instance of a Redis
        client class (`redis.asyncio.Redis`), allowing the object
        to interact with a Redis server for caching purposes.

        Parameters:
            redis_ (Any): An instance of a Redis client class
                (`redis.asyncio.Redis`) to be used for caching.
                This allows the object to communicate with a
                Redis server for caching operations.
            ttl (int, optional): Time-to-live (TTL) for cached items in seconds.
                If provided, it sets the time duration for how long cached
                items will remain valid. If not provided, cached items will not
                have an automatic expiration.
        r   r6   z\Could not import `redis.asyncio` python package. Please install it with `pip install redis`.z1Please pass a valid `redis.asyncio.Redis` client.N)redis.asyncior7   r   r   r[   r   r   r   s       rD   rv   zAsyncRedisCache.__init__  s    &	+++++++ 	 	 	>  	
 &%(( 	RPQQQ
r   rw   r<   rx   r=   ry   c                     t          d          )r|   zjThis async Redis cache does not implement `lookup()` method. Consider using the async `alookup()` version.NotImplementedErrorr~   s      rD   r   zAsyncRedisCache.lookup"      !<
 
 	
rF   c                  K   	 | j                             |                     ||                     d{V }|                     |          S # t          $ r(}t
                              d|            Y d}~dS d}~ww xY w)z6Look up based on prompt and llm_string. Async version.NzRedis async lookup failed: r  r  s        rD   r   zAsyncRedisCache.alookup)  s      	 J..tyy/L/LMMMMMMMMG((111 	 	 	LL:q::;;;44444	s   AA 
A?A::A?r   r&   rp   c                     t          d          )r   zjThis async Redis cache does not implement `update()` method. Consider using the async `aupdate()` version.r%  r   s       rD   r   zAsyncRedisCache.update2  r'  rF   c                  K   |                      |           |                     ||          }	 | j                                        4 d{V }|                     |||| j                   |                                 d{V  ddd          d{V  dS # 1 d{V swxY w Y   dS # t          $ r(}t          	                    d|            Y d}~dS d}~ww xY w)z;Update cache based on prompt and llm_string. Async version.NzRedis async update failed: r  r  s          rD   r   zAsyncRedisCache.aupdate9  s      	$$Z000ii
++	<z**,, % % % % % % %33Cz48TTTllnn$$$$$$$% % % % % % % % % % % % % % % % % % % % % % % % % % % % % %  	< 	< 	<LL:q::;;;;;;;;;	<s;   B, 8BB, 
B##B, &B#'B, ,
C6CCr   c                     t          d          )r  zhThis async Redis cache does not implement `clear()` method. Consider using the async `aclear()` version.r%  r   s     rD   r   zAsyncRedisCache.clearF  s    !;
 
 	
rF   c                   K   	 |                     dd          } | j        j        dd|i| d{V  dS # t          $ r(}t                              d|            Y d}~dS d}~ww xY w)zf
        Clear cache. If `asynchronous` is True, flush asynchronously.
        Async version.
        r   FNzRedis async clear failed: rJ   r  r  s       rD   r   zAsyncRedisCache.aclearM  s      
	;!::ne<<L$$*$II,I&IIIIIIIIIII 	; 	; 	;LL9a99:::::::::	;s   06 
A( A##A(r   r   r   r   )r   r   r   r   rv   r   r   r   r   r   r   rJ   rF   rD   r!  r!    s         
 =A      >
 
 
 
   
 
 
 
< < < <
 
 
 
	; 	; 	; 	; 	; 	;rF   r!  c                  d    e Zd ZdZdddigddiddigdZ	 dddZddZddZd dZd!dZ	d"dZ
dS )#RedisSemanticCachez0Cache that uses Redis as a vector-store backend.rw   namer   rx   )content_keyr   extra皙?	redis_urlr<   	embeddingr(   score_thresholdfloatc                >    i | _         || _        || _        || _        dS )a  Initialize by passing in the `init` GPTCache func

        Args:
            redis_url (str): URL to connect to Redis.
            embedding (Embedding): Embedding provider for semantic encoding and search.
            score_threshold (float, 0.2):

        Example:

        .. code-block:: python

            from langchain_community.globals import set_llm_cache

            from langchain_community.cache import RedisSemanticCache
            from langchain_community.embeddings import OpenAIEmbeddings

            set_llm_cache(RedisSemanticCache(
                redis_url="redis://localhost:6379",
                embedding=OpenAIEmbeddings()
            ))

        N)_cache_dictr3  r4  r5  )ru   r3  r4  r5  s       rD   rv   zRedisSemanticCache.__init__f  s(    2 9;"".rF   r=   c                *    t          |          }d| S Nzcache:r   ru   rx   hashed_indexs      rD   _index_namezRedisSemanticCache._index_name      Z((&&&&rF   RedisVectorstorec           
        |                      |          }|| j        v r| j        |         S 	 t          j        | j        || j        t          t          | j                            | j        |<   n# t          $ r t          | j        || j        t          t          | j                            }| j        
                    d          }|                    t          |                     || j        |<   Y nw xY w| j        |         S )N)r4  
index_namer3  schema)r4  rA  r3  index_schematestr   )dim)r=  r8  r?  from_existing_indexr4  r3  r   r   DEFAULT_SCHEMAr[   embed_query_create_index_if_not_existlen)ru   rx   rA  r   
_embeddings        rD   _get_llm_cachez!RedisSemanticCache._get_llm_cache  s   %%j11
 )))#J//	1+;+O.%.D$"566	, , ,DZ((  		1 		1 		1$.%.!$(;<<	  E 333@@J,,Z,AAA+0DZ(((		1 
++s   AA0 0BC:9C:r   r
   rp   c                    |                      |d                   }|| j        v r2| j        |                             |d| j                   | j        |= dS dS ),Clear semantic cache for a given llm_string.rx   T)rA  delete_documentsr3  N)r=  r8  
drop_indexr3  ru   r   rA  s      rD   r   zRedisSemanticCache.clear  sq    %%f\&:;;
)))Z(33% 4     ,,,	 *)rF   ry   c                   |                      |          }g }|                    |d| j                  }|r|D ]}	 |                    t	          |j        d                              1# t          $ rJ t                              d           |                    t          |j        d                              Y w xY w|r|ndS )r|      )r   kdistance_thresholdr   r   N
rL  similarity_searchr5  extendr/   r   r   rj   rk   r]   ru   rw   rx   	llm_cacherG   r\   documents          rD   r   zRedisSemanticCache.lookup  s   ''
33	--#3 . 
 

  	#  &&uX->|-L'M'MNNNN    NN!    &&3H4El4STT     *3{{t3   -A**AB>=B>r&   c                   |D ]6}t          |t                    st          dt          |                     7|                     |          }||t          d |D                       d}|                    |g|g           dS )r   zHRedisSemanticCache only supports caching of normal LLM generations, got c                    g | ]}|S rJ   rJ   rL   gs     rD   rN   z-RedisSemanticCache.update.<locals>.<listcomp>       7 7 7q 7 7 7rF   rx   rw   r   texts	metadatasNr   r1   r[   r   rL  r-   	add_textsru   rw   rx   r   r   rZ  r   s          rD   r   zRedisSemanticCache.update  s     	 	Cc:..  ?3799? ?  
 ''
33	 % 7 7J 7 7 788
 

 	6(xjAAAAArF   Nr2  )r3  r<   r4  r(   r5  r6  rx   r<   r=   r<   )rx   r<   r=   r?  r   r   r   )r   r   r   r   rG  rv   r=  rL  r   r   r   rJ   rF   rD   r.  r.  Y  s        ::
  X
 <(6<*@A N OR/ / / / /<' ' ' ', , , ,8- - - -4 4 4 48B B B B B BrF   r.  c                  F    e Zd ZdZ	 dddZdd
ZddZddZddZddZ	dS )GPTCachez&Cache that uses GPTCache as a backend.N	init_func>Union[Callable[[Any, str], None], Callable[[Any], None], None]c                h    	 ddl }n# t          $ r t          d          w xY w|| _        i | _        dS )a  Initialize by passing in init function (default: `None`).

        Args:
            init_func (Optional[Callable[[Any], None]]): init `GPTCache` function
            (default: `None`)

        Example:
        .. code-block:: python

            # Initialize GPTCache with a custom init function
            import gptcache
            from gptcache.processor.pre import get_prompt
            from gptcache.manager.factory import get_data_manager
            from langchain_community.globals import set_llm_cache

            # Avoid multiple caches using the same file,
            causing different llm model caches to affect each other

            def init_gptcache(cache_obj: gptcache.Cache, llm str):
                cache_obj.init(
                    pre_embedding_func=get_prompt,
                    data_manager=manager_factory(
                        manager="map",
                        data_dir=f"map_cache_{llm}"
                    ),
                )

            set_llm_cache(GPTCache(init_gptcache))

        r   NzXCould not import gptcache python package. Please install it with `pip install gptcache`.)gptcacher   init_gptcache_funcgptcache_dict)ru   rm  rp  s      rD   rv   zGPTCache.__init__  sc    H	OOOO 	 	 	A  	  	 .0s    !rx   r<   r=   r
   c                ^   ddl m} ddlm} ddlm}  |            }| j        ^t          j        | j                  }t          |j
                  dk    r|                     ||           n7|                     |           n!|                    | ||                     || j        |<   |S )	zNew gptcache objectr   Cache)get_data_manager)
get_promptN   )	data_path)pre_embedding_funcdata_manager)rp  ru  gptcache.manager.factoryrv  gptcache.processor.prerw  rq  inspect	signaturerJ  
parametersinitrr  )ru   rx   ru  rv  rw  	_gptcachesigs          rD   _new_gptcachezGPTCache._new_gptcache  s    """"""======555555EGG	".#D$;<<C3>""a''''	:>>>>''	2222NN#---
CCC    
 *3:&rF   c                j    | j                             |d          }|s|                     |          }|S )zgGet a cache object.

        When the corresponding llm model cache does not exist, it will be created.N)rr  r}   r  )ru   rx   r  s      rD   _get_gptcachezGPTCache._get_gptcache%  s=     &**:t<<	 	7**:66IrF   rw   ry   c                x    ddl m} |                     |          } |||          }|t          |          ndS )zLook up the cache data.
        First, retrieve the corresponding cache object using the `llm_string` parameter,
        and then retrieve the data from the cache based on the `prompt`.
        r   )r}   	cache_objN)gptcache.adapter.apir}   r  rm   )ru   rw   rx   r}   r  ress         rD   r   zGPTCache.lookup.  sU    
 	-,,,,,&&z22	c&I...*-/!#&&&tCrF   r   r&   rp   c                    |D ]6}t          |t                    st          dt          |                     7ddlm} |                     |          }t          |          } ||||           dS )zUpdate cache.
        First, retrieve the corresponding cache object using the `llm_string` parameter,
        and then store the `prompt` and `return_val` in the cache object.
        z>GPTCache only supports caching of normal LLM generations, got r   )putr  N)r   r1   r[   r   r  r  r  ra   )ru   rw   rx   r   r   r  r  handled_datas           rD   r   zGPTCache.update:  s    
  	 	Cc:..  '99' '  
 	-,,,,,&&z22	)*55FLI6666trF   r   c                    ddl m} | j                                        D ]&}t	          ||          }|                                 '| j                                         dS )r   r   rt  N)rp  ru  rr  r   r   flushr   )ru   r   ru  gptcache_instances       rD   r   zGPTCache.clearL  st    """"""!%!3!:!:!<!< 	& 	& $U,= > >##%%%%  """""rF   r  )rm  rn  )rx   r<   r=   r
   r   r   r   )
r   r   r   r   rv   r  r  r   r   r   rJ   rF   rD   rl  rl    s        00 	/0 /0 /0 /0 /0b   ,   
D 
D 
D 
D   $# # # # # #rF   rl  cache_clientmomento.CacheClient
cache_namerp   c                    ddl m} |                     |          }t          ||j                  st          ||j                  rdS t          ||j                  r|j        t          d|           )zCreate cache if it doesn't exist.

    Raises:
        SdkException: Momento service or network error
        Exception: Unexpected response
    r   )CreateCacheNz$Unexpected response cache creation: )	momento.responsesr  create_cacher   SuccessCacheAlreadyExistsErrorinner_exceptionr   )r  r  r  create_cache_responses       rD   _ensure_cache_existsr  W  s     .-----(55jAA')<== X{=B B X t	);+<	=	= X#33V?TVVWWWrF   r   Optional[timedelta]c                \    | '| t          d          k    rt          d|  d          d S d S )Nr   )secondszttl must be positive but was .)r   r[   r   s    rD   _validate_ttlr  k  sC    
3)A"6"6"666????@@@ 66rF   c                  d    e Zd ZdZdddd#dZeddddd$d            Zd%dZd&dZd'd!Z	d(d"Z
dS ))MomentoCachez@Cache that uses Momento as a backend. See https://gomomento.com/NT)r   ensure_cache_existsr  r  r  r<   r   r  r  boolc                   	 ddl m} n# t          $ r t          d          w xY wt          ||          st	          d          t          |           |rt          ||           || _        || _        || _	        dS )aU  Instantiate a prompt cache using Momento as a backend.

        Note: to instantiate the cache client passed to MomentoCache,
        you must have a Momento account. See https://gomomento.com/.

        Args:
            cache_client (CacheClient): The Momento cache client.
            cache_name (str): The name of the cache to use to store the data.
            ttl (Optional[timedelta], optional): The time to live for the cache items.
                Defaults to None, ie use the client default TTL.
            ensure_cache_exists (bool, optional): Create the cache if it doesn't
                exist. Defaults to True.

        Raises:
            ImportError: Momento python package is not installed.
            TypeError: cache_client is not of type momento.CacheClientObject
            ValueError: ttl is non-null and non-negative
        r   )CacheClientVCould not import momento python package. Please install it with `pip install momento`.z2cache_client must be a momento.CacheClient object.N)
momentor  r   r   ri   r  r  r  r  r   )ru   r  r  r   r  r  s         rD   rv   zMomentoCache.__init__s  s    4	+++++++ 	 	 	@  	
 ,44 	RPQQQc 	; z:::($r   )configurationapi_key
auth_tokenr   r  &Optional[momento.config.Configuration]r  Optional[str]r  r   r
   r=   c               T   	 ddl m}m}m}	 n# t          $ r t	          d          w xY w||j                                        }	 |pt          dd          }n"# t          $ r |pt          dd          }Y nw xY w|		                    |          }
 |||
|	          } | ||fd
|i|S )z,Construct cache from CacheClient parameters.r   )r  ConfigurationsCredentialProviderr  Nr  MOMENTO_AUTH_TOKENr  MOMENTO_API_KEY)default_ttlr   )
r  r  r  r  r   Laptopv1r2   r[   from_string)clsr  r   r  r  r  r   r  r  r  credentialsr  s               rD   from_client_paramszMomentoCache.from_client_params  s   	OOOOOOOOOOO 	 	 	@  	
  *14466M	L TL?S$T$TGG 	L 	L 	LKi9J!K!KGGG	L(44W=="{=+3OOOs<??????s   
 'A A87A8rw   rx   c                &    t          ||z             S )a  Compute cache key from prompt and associated model and settings.

        Args:
            prompt (str): The prompt run through the language model.
            llm_string (str): The language model version and settings.

        Returns:
            str: The cache key.
        r   r~   s      rD   __keyzMomentoCache.__key  s     Vj()))rF   ry   c                B   ddl m} g }| j                            | j        |                     ||                    }t          ||j                  r|j        }t          |          }n2t          ||j
                  rnt          ||j                  r|j        |r|ndS )a  Lookup llm generations in cache by prompt and associated model and settings.

        Args:
            prompt (str): The prompt run through the language model.
            llm_string (str): The language model version and settings.

        Raises:
            SdkException: Momento service or network error

        Returns:
            Optional[RETURN_VAL_TYPE]: A list of language model generations.
        r   )CacheGetN)r  r  r  r}   r  _MomentoCache__keyr   Hitvalue_stringr]   Missr  r  )ru   rw   rx   r  rG   get_responsevalues          rD   r   zMomentoCache.lookup  s     	/.....')(,,OTZZ
;;
 
 lHL11 	/ -E5e<<KKhm44 	/hn55 	/..)3{{t3rF   r   r&   rp   c                   |D ]6}t          |t                    st          dt          |                     7|                     ||          }t          |          }| j                            | j        ||| j	                  }ddl
m} t          ||j                  rdS t          ||j                  r|j        t          d|           )a|  Store llm generations in cache.

        Args:
            prompt (str): The prompt run through the language model.
            llm_string (str): The language model string.
            return_val (RETURN_VAL_TYPE): A list of language model generations.

        Raises:
            SdkException: Momento service or network error
            Exception: Unexpected response
        z=Momento only supports caching of normal LLM generations, got r   )CacheSetzUnexpected response: N)r   r1   r[   r   r  rR   r  setr  r   r  r  r  r  r  r   )	ru   rw   rx   r   r   r   r  set_responser  s	            rD   r   zMomentoCache.update  s      	 	Cc:..  '99' '  
 jj,,)*55(,,T_c5$(SS......lH$455 	DDhn55 	D..BLBBCCCrF   c                    ddl m} | j                            | j                  }t          ||j                  rdS t          ||j                  r|j        dS )zeClear the cache.

        Raises:
            SdkException: Momento service or network error
        r   )
CacheFlushN)	r  r  r  flush_cacher  r   r  r  r  )ru   r   r  flush_responses       rD   r   zMomentoCache.clear  sp     	100000*66tGGnj&899 	1D
(899 	1 00	1 	1rF   )r  r  r  r<   r   r  r  r  )r  r<   r   r   r  r  r  r  r  r  r   r
   r=   r  r   r   r   r   )r   r   r   r   rv   classmethodr  r  r   r   r   rJ   rF   rD   r  r  p  s        JJ $($() ) ) ) ) )V  AE!%$(@ @ @ @ @ [@<
* 
* 
* 
*4 4 4 4:D D D D<1 1 1 1 1 1rF   r  langchain_llm_cachec                  v    e Zd ZdZddeedej        fd&dZd'dZ	d'dZ
d(dZd(dZ	 d)d*d Zd+d!Zd,d$Zd,d%ZdS )-CassandraCachea  
    Cache that uses Cassandra / Astra DB as a backend.

    Example:

        .. code-block:: python

            import cassio

            from langchain_community.cache import CassandraCache
            from langchain_core.globals import set_llm_cache

            cassio.init(auto=True)  # Requires env. variables, see CassIO docs

            set_llm_cache(CassandraCache())

    It uses a single Cassandra table.
    The lookup keys (which get to form the primary key) are:
        - prompt, a string
        - llm_string, a deterministic str representation of the model parameters.
          (needed to prevent same-prompt-different-model collisions)

    Args:
        session: an open Cassandra session.
            Leave unspecified to use the global cassio init (see below)
        keyspace: the keyspace to use for storing the cache.
            Leave unspecified to use the global cassio init (see below)
        table_name: name of the Cassandra table to use as cache
        ttl_seconds: time-to-live for cache entries
            (default: None, i.e. forever)
        setup_mode: a value in langchain_community.utilities.cassandra.SetupMode.
            Choose between SYNC, ASYNC and OFF - the latter if the Cassandra
            table is guaranteed to exist already, for a faster initialization.

    Note:
        The session and keyspace parameters, when left out (or passed as None),
        fall back to the globally-available cassio settings if any are available.
        In other words, if a previously-run 'cassio.init(...)' has been
        executed previously anywhere in the code, Cassandra-based objects
        need not specify the connection parameters at all.
    NFr   Optional[CassandraSession]keyspacer  
table_namer<   ttl_secondsr   skip_provisioningr  
setup_modeCassandraSetupModec                h   |rt          dddd           	 ddlm} n$# t          t          f$ r t          d          w xY w|| _        || _        || _        || _        i }|t          j
        k    rd|d	<    |d| j        | j        | j        d
dgddg| j        |p|t          j        k    d|| _        d S )N0.0.33r  @setup_mode=langchain_community.utilities.cassandra.SetupMode.OFFTr/  alternativependingr   )ElasticCassandraTableWCould not import cassio python package. Please install it with `pip install -U cassio`.async_setuprx   rw   TEXT)r   r  tablekeysprimary_key_typer  r  rJ   )r%   cassio.tabler  r   ModuleNotFoundErrorr   r  r  r  r  r   OFFkv_cache)	ru   r   r  r  r  r  r  r  r   s	            rD   rv   zCassandraCache.__init__B  s!     	(V   	:::::::01 	 	 	B  	  $&+111$(F=!-- 	
L]/)$f-(/W:ASAW3W	
 	
 	
 	
s    !?rw   rx   r=   ry   c                    | j                             t          |          t          |                    }|t          |d                   S d S Nrx   rw   	body_blob)r  r}   rE   rm   ru   rw   rx   r   s       rD   r   zCassandraCache.lookupp  sR    }  Z((== ! 
 
 %d;&78884rF   c                   K   | j                             t          |          t          |                     d {V }|t          |d                   S d S r  )r  agetrE   rm   r  s       rD   r   zCassandraCache.alookupz  st      ]''Z((== ( 
 
 
 
 
 
 
 
 %d;&78884rF   r   r&   rp   c                    t          |          }| j                            t          |          t          |          |           d S N)rx   rw   r  )ra   r  r  rE   ru   rw   rx   r   blobs        rD   r   zCassandraCache.update  sO    !*--Z((== 	 	
 	
 	
 	
 	
rF   c                   K   t          |          }| j                            t          |          t          |          |           d {V  d S r  )ra   r  aputrE   r  s        rD   r   zCassandraCache.aupdate  ss       "*--m  Z((== ! 
 
 	
 	
 	
 	
 	
 	
 	
 	
 	
rF   r   r)   stopOptional[List[str]]c                    t          i |                                d|ig           d         }|                     ||          S z
        A wrapper around `delete` with the LLM being passed.
        In case the llm.invoke(prompt) calls have a `stop` param, you should
        pass it here
        r  rS  rx   r+   rK   r   ru   rw   r   r  rx   s        rD   delete_through_llmz!CassandraCache.delete_through_llm  Q     !,sxxzz,fd^,
 
 
 {{6j{999rF   c                n    | j                             t          |          t          |                    S )%Evict from cache if there's an entry.r  )r  r   rE   r~   s      rD   r   zCassandraCache.delete  s5    }##Z((== $ 
 
 	
rF   r   r
   c                8    | j                                          dS z*Clear cache. This is for all LLMs at once.N)r  r   r   s     rD   r   zCassandraCache.clear  s    rF   c                H   K   | j                                          d{V  dS r  )r  r   r   s     rD   r   zCassandraCache.aclear  s2      m""$$$$$$$$$$$rF   )r   r  r  r  r  r<   r  r   r  r  r  r  r   r   r  rw   r<   r   r)   r  r  r=   rp   rw   r<   rx   r<   r=   rp   r   )r   r   r   r   "CASSANDRA_CACHE_DEFAULT_TABLE_NAME#CASSANDRA_CACHE_DEFAULT_TTL_SECONDSr  r   rv   r   r   r   r   r  r   r   r   rJ   rF   rD   r  r    s        ( (X /3"&<%H"');)@,
 ,
 ,
 ,
 ,
\      
 
 
 

 
 
 
 BF: : : : :
 
 
 
   % % % % % %rF   r  dotg333333?langchain_llm_semantic_cache   c            
          e Zd ZdZdddedeedeej	        f
d5dZ
d6dZd6dZd7d Zd7d!Zd8d#Zd8d$Zd9d&Zd9d'Z	 d:d;d,Z	 d:d;d-Zd<d/Zd<d0Zd=d3Zd=d4ZdS )>CassandraSemanticCachea  
    Cache that uses Cassandra as a vector-store backend for semantic
    (i.e. similarity-based) lookup.

    Example:

        .. code-block:: python

            import cassio

            from langchain_community.cache import CassandraSemanticCache
            from langchain_core.globals import set_llm_cache

            cassio.init(auto=True)  # Requires env. variables, see CassIO docs

            my_embedding = ...

            set_llm_cache(CassandraSemanticCache(
                embedding=my_embedding,
                table_name="my_semantic_cache",
            ))

    It uses a single (vector) Cassandra table and stores, in principle,
    cached values from several LLMs, so the LLM's llm_string is part
    of the rows' primary keys.

    One can choose a similarity measure (default: "dot" for dot-product).
    Choosing another one ("cos", "l2") almost certainly requires threshold tuning.
    (which may be in order nevertheless, even if sticking to "dot").

    Args:
        session: an open Cassandra session.
            Leave unspecified to use the global cassio init (see below)
        keyspace: the keyspace to use for storing the cache.
            Leave unspecified to use the global cassio init (see below)
        embedding: Embedding provider for semantic
            encoding and search.
        table_name: name of the Cassandra (vector) table
            to use as cache. There is a default for "simple" usage, but
            remember to explicitly specify different tables if several embedding
            models coexist in your app (they cannot share one cache table).
        distance_metric: an alias for the 'similarity_measure' parameter (see below).
            As the "distance" terminology is misleading, please prefer
            'similarity_measure' for clarity.
        score_threshold: numeric value to use as
            cutoff for the similarity searches
        ttl_seconds: time-to-live for cache entries
            (default: None, i.e. forever)
        similarity_measure: which measure to adopt for similarity searches.
            Note: this parameter is aliased by 'distance_metric' - however,
            it is suggested to use the "similarity" terminology since this value
            is in fact a similarity (i.e. higher means closer).
            Note that at most one of the two parameters 'distance_metric'
            and 'similarity_measure' can be provided.
        setup_mode: a value in langchain_community.utilities.cassandra.SetupMode.
            Choose between SYNC, ASYNC and OFF - the latter if the Cassandra
            table is guaranteed to exist already, for a faster initialization.

    Note:
        The session and keyspace parameters, when left out (or passed as None),
        fall back to the globally-available cassio settings if any are available.
        In other words, if a previously-run 'cassio.init(...)' has been
        executed previously anywhere in the code, Cassandra-based objects
        need not specify the connection parameters at all.
    NFr   r  r  r  r4  Optional[Embeddings]r  r<   distance_metricr5  r6  r  r   r  r  similarity_measurer  r  c                    |rt          dddd           	 ddlm} n$# t          t          f$ r t          d          w xY w|st          d	          |t          dd
dd           |}	| _        | _        | _        | _	        |	 _
        | _        | _        t          t                    d fd            }| _        t!          t                    d fd            }| _        d }|
t$          j        k    r                                 }n$|
t$          j        k    r                                 }i }|
t$          j        k    rd|d<    |d j         j         j	        dg| j        ddhf|p|
t$          j        k    d| _        d S )Nr  r  r  Tr  r   )MetadataVectorCassandraTabler  z'Missing required parameter 'embedding'.r  r  maxsizer   r<   r=   List[float]c                :    j                             |           S Nr   r4  rH  r   ru   s    rD   _cache_embeddingz9CassandraSemanticCache.__init__.<locals>._cache_embedding8      >--4-888rF   c                J   K   j                             |            d {V S r  r4  aembed_queryr  s    rD   _acache_embeddingz:CassandraSemanticCache.__init__.<locals>._acache_embedding>  2      44$4?????????rF   r  r  allow_llm_string_hash)r   r  r  r  vector_dimensionr  metadata_indexingr  r   r<   r=   r  rJ   )r%   r  r  r   r  r[   r   r  r4  r  r  r5  r  r   -CASSANDRA_SEMANTIC_CACHE_EMBEDDING_CACHE_SIZE_get_embedding_async_lru_cache_aget_embeddingr  r   _aget_embedding_dimensionr   _get_embedding_dimensionr  r  )ru   r   r  r4  r  r  r5  r  r  r  r  r  r  r   embedding_dimensionr   s   `               rD   rv   zCassandraSemanticCache.__init__  s[     	(V   	AAAAAAA01 	 	 	B  	  	HFGGG &&0	    "1 "$"4.& 
H	I	I	I	9 	9 	9 	9 	9 
J	I	9 /	"O	P	P	P	@ 	@ 	@ 	@ 	@ 
Q	P	@  1@D+111"&"@"@"B"B-222"&"?"?"A"A+111$(F=!11 

L]/$X0(&);(<=/W:ASAW3W

 

 

 




s	    !A r=   intc                H    t          |                     d                    S NzThis is a sample sentence.r   rJ  r(  rt   s    rD   r,  z/CassandraSemanticCache._get_embedding_dimensionZ  "    4&&,H&IIJJJrF   c                X   K   t          |                     d           d {V           S r0  rJ  r*  rt   s    rD   r+  z0CassandraSemanticCache._aget_embedding_dimension]  8      --3O-PPPPPPPPQQQrF   rw   rx   r   r&   rp   c                    |                      |          }t          |          }t          |          }||d}t          |           d| }| j                            ||||           d S Nr   )_promptr#  -)r  vectorrow_idr   )r(  rE   ra   r  r  	ru   rw   rx   r   embedding_vectorllm_string_hashbodyr   r;  s	            rD   r   zCassandraSemanticCache.update`  s    ..F.;;
++!*-- /
 
 &MM55O55
#	 	 	
 	
 	
 	
 	
rF   c                   K   |                      |           d {V }t          |          }t          |          }||d}t          |           d| }| j                            ||||           d {V  d S r7  )r*  rE   ra   r  r  r<  s	            rD   r   zCassandraSemanticCache.aupdateq  s       "&!5!56!5!B!BBBBBBB
++!*-- /
 
 &MM55O55joo#	  
 
 	
 	
 	
 	
 	
 	
 	
 	
 	
rF   ry   c                F    |                      ||          }||d         S d S NrS  lookup_with_idru   rw   rx   hit_with_ids       rD   r   zCassandraSemanticCache.lookup  ,    ))&*=="q>!4rF   c                V   K   |                      ||           d {V }||d         S d S rB  alookup_with_idrE  s       rD   r   zCassandraSemanticCache.alookup  B       00DDDDDDDD"q>!4rF   %Optional[Tuple[str, RETURN_VAL_TYPE]]c           	        |                      |          }t          | j                            |dt	          |          id| j        | j                            }|r+|d         }t          |d                   }|
|d         |fS dS dS )	w
        Look up based on prompt and llm_string.
        If there are hits, return (document_id, cached_entry)
        r   r#  rS  r:  r   nmetricmetric_thresholdr   r  Nr;  )r(  listr  metric_ann_searchrE   r  r5  rm   ru   rw   rx   prompt_embeddinghitshitrG   s          rD   rD  z%CassandraSemanticCache.lookup_with_id  s     )-(;(;(;(H(HJ((',eJ.?.?@.!%!5 )  
 
  	q'C,S-=>>K& M 
 t4rF   c           	     2  K   |                      |           d{V }t          | j                            |dt	          |          id| j        | j                   d{V           }|r+|d         }t          |d                   }|
|d         |fS dS dS )	rN  r   Nr#  rS  rO  r   r  r;  )r*  rS  r  ametric_ann_searchrE   r  r5  rm   rU  s          rD   rJ  z&CassandraSemanticCache.alookup_with_id  s       /3.B.B.B.O.O(O(O(O(O(O(O*//',eJ.?.?@.!%!5 0        
 
  	q'C,S-=>>K& M 
 t4rF   r   r)   r  r  c                    t          i |                                d|ig           d         }|                     ||          S Nr  rS  r  r+   rK   rD  r  s        rD   lookup_with_id_through_llmz1CassandraSemanticCache.lookup_with_id_through_llm  T     !,sxxzz,fd^,
 
 
 ""6j"AAArF   c                   K   t          i |                                d|ig            d {V d         }|                     ||           d {V S r\  r*   rK   rJ  r  s        rD   alookup_with_id_through_llmz2CassandraSemanticCache.alookup_with_id_through_llm         0388::0&$0        
 ))&Z)HHHHHHHHHrF   document_idc                <    | j                             |           dS 
        Given this is a "similarity search" cache, an invalidation pattern
        that makes sense is first a lookup to get an ID, and then deleting
        with that ID. This is for the second step.
        )r;  N)r  r   ru   rd  s     rD   delete_by_document_idz,CassandraSemanticCache.delete_by_document_id  s#     	
-----rF   c                L   K   | j                             |           d{V  dS rf  )r  adeleterh  s     rD   adelete_by_document_idz-CassandraSemanticCache.adelete_by_document_id  s9       j   44444444444rF   r   r
   c                8    | j                                          dS z!Clear the *whole* semantic cache.N)r  r   r   s     rD   r   zCassandraSemanticCache.clear  s    
rF   c                H   K   | j                                          d{V  dS rn  )r  r   r   s     rD   r   zCassandraSemanticCache.aclear  s2      j!!!!!!!!!!!rF   )r   r  r  r  r4  r  r  r<   r  r  r5  r6  r  r   r  r  r  r<   r  r  r=   r.  r   r   rw   r<   rx   r<   r=   rL  r  rw   r<   r   r)   r  r  r=   rL  rd  r<   r=   rp   r   )r   r   r   r   +CASSANDRA_SEMANTIC_CACHE_DEFAULT_TABLE_NAME0CASSANDRA_SEMANTIC_CACHE_DEFAULT_SCORE_THRESHOLD,CASSANDRA_SEMANTIC_CACHE_DEFAULT_TTL_SECONDS0CASSANDRA_SEMANTIC_CACHE_DEFAULT_DISTANCE_METRICr  r   rv   r,  r+  r   r   r   r   rD  rJ  r^  rb  ri  rl  r   r   rJ   rF   rD   r  r    s       @ @H /3"&*.E)-!Q%Q"'"R);)@Y
 Y
 Y
 Y
 Y
vK K K KR R R R
 
 
 
"
 
 
 
&         >   @ BFB B B B B BF	I 	I 	I 	I 	I. . . .5 5 5 5   " " " " " "rF   r  c                      e Zd ZdZdZ eed          Z eed          Z eed          Z	 ee
d          Z ee          Z ee          ZdS )FullMd5LLMCacher   full_md5_llm_cacheTr   )indexN)r   r   r   r   r   r   r   id
prompt_md5r   r   r   rw   r   rJ   rF   rD   ry  ry    s        <<(M	D	)	)	)Bd+++J
&t
$
$
$C
&
%
%
%CVF^^Fvf~~HHHrF   ry  c                  ^    e Zd ZdZefddZddZddZddZd dZ	d!dZ
ed"d            ZdS )#SQLAlchemyMd5Cacher   r   r   r   Type[FullMd5LLMCache]c                j    || _         || _        | j        j                            | j                    dS r   r   r   s      rD   rv   zSQLAlchemyMd5Cache.__init__  s5     ("--dk:::::rF   rw   r<   rx   r=   ry   c                N    |                      ||          }|rd |D             S dS )r|   c                8    g | ]}t          |d                    S r   r.   r   s     rD   rN   z-SQLAlchemyMd5Cache.lookup.<locals>.<listcomp>  s"    222cE#a&MM222rF   N)_search_rows)ru   rw   rx   r   s       rD   r   zSQLAlchemyMd5Cache.lookup  s8      44 	322T2222trF   r   r&   rp   c                    t           j                  5 }|                                5                       |                                           fdt          |          D             }|D ]}|                    |           	 ddd           n# 1 swxY w Y   ddd           dS # 1 swxY w Y   dS )r   c                    g | ]K\  }}                     t          t          j                              t	          |          |           LS ))r|  rw   r}  r   r   r   )r   r<   uuiduuid1r-   )rL   r   r   rx   rw   r}  ru   s      rD   rN   z-SQLAlchemyMd5Cache.update.<locals>.<listcomp>   sj     
 
 
 As !!4:<<((!)""3ZZ "  
 
 
rF   N)r   r   r   _delete_previousget_md5r   r   )ru   rw   rx   r   r   r   r   r}  s   ```    @rD   r   zSQLAlchemyMd5Cache.update  sn   T[!! 	$Wgmmoo 	$ 	$!!'6:>>>f--J
 
 
 
 
 
 
 (
33
 
 
E  $ $d####$	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$ 	$s5   B8A%B B8 B$	$B8'B$	(B88B<?B<r   r   c                D   t          | j                                      | j        j        |                     |          k                                  | j        j        |k                                  | j        j        |k              }|                    |           d S r  )r   r   r   r}  r  r   rw   r   )ru   r   rw   rx   r   s        rD   r  z#SQLAlchemyMd5Cache._delete_previous.  s    4$%%U4$/4<<3G3GGHHU4$(J677U4$+v566	 	 	rF   Sequence[Row]c                   |                      |          }t          | j        j                                      | j        j        |k                                  | j        j        |k                                  | j        j        |k                                  | j        j	                  }t          | j                  5 }|                    |                                          cd d d            S # 1 swxY w Y   d S r  )r  r   r   r   r   r}  r   rw   r   r   r   r   r   r   )ru   rw   rx   
prompt_pd5r   r   s         rD   r  zSQLAlchemyMd5Cache._search_rows7  s   \\&))
4$-..U4$/:=>>U4$(J677U4$+v566Xd'+,, 	 T[!! 	4W??4((1133	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4s   'C77C;>C;r   r
   c                    t          | j                  5 }|                    | j                                                   ddd           dS # 1 swxY w Y   dS r   )r   r   r   r   r   r   s      rD   r   zSQLAlchemyMd5Cache.clearC  s    T[!! 	8WOOD-4466777	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8 	8s   -AAAinput_stringc                r    t          j        |                                                                           S r  r?   )r  s    rD   r  zSQLAlchemyMd5Cache.get_md5H  s*    {<..0011;;===rF   N)r   r   r   r  r   r   )r   r   rw   r<   rx   r<   r=   rp   )rw   r<   rx   r<   r=   r  r   )r  r<   r=   r<   )r   r   r   r   ry  rv   r   r   r  r  r   r  r  rJ   rF   rD   r  r  	  s        11 ET; ; ; ; ;   $ $ $ $&   
4 
4 
4 
48 8 8 8
 > > > \> > >rF   r  langchain_astradb_cachez0.0.28z1.0zlangchain_astradb.AstraDBCache)sinceremovalalternative_importc            	          e Zd Zed+d            Zeddddddej        dd,dZd-dZ	d-dZ
d.dZd.dZ	 d/d0d#Z	 d/d0d$Zd1d%Zd1d&Zd2d)Zd2d*ZdS )3AstraDBCacherw   r<   rx   r=   c                D    t          |            dt          |           S N#r   r  s     rD   _make_idzAstraDBCache._make_idV  $    --55%
"3"3555rF   NF)collection_nametokenapi_endpointastra_db_clientasync_astra_db_client	namespacepre_delete_collectionr  r  r  r  r  r  Optional[AstraDB]r  Optional[AsyncAstraDB]r  r  r  r  AstraSetupModec          
         t          ||||||||          | _        | j        j        | _        | j        j        | _        dS )al  
        Cache that uses Astra DB as a backend.

        It uses a single collection as a kv store
        The lookup keys, combined in the _id of the documents, are:
            - prompt, a string
            - llm_string, a deterministic str representation of the model parameters.
              (needed to prevent same-prompt-different-model collisions)

        Args:
            collection_name: name of the Astra DB collection to create/use.
            token: API token for Astra DB usage.
            api_endpoint: full URL to the API endpoint,
                such as `https://<DB-ID>-us-east1.apps.astra.datastax.com`.
            astra_db_client: *alternative to token+api_endpoint*,
                you can pass an already-created 'astrapy.db.AstraDB' instance.
            async_astra_db_client: *alternative to token+api_endpoint*,
                you can pass an already-created 'astrapy.db.AsyncAstraDB' instance.
            namespace: namespace (aka keyspace) where the
                collection is created. Defaults to the database's "default namespace".
            setup_mode: mode used to create the Astra DB collection (SYNC, ASYNC or
                OFF).
            pre_delete_collection: whether to delete the collection
                before creating it. If False and the collection already exists,
                the collection will be used as is.
        )r  r  r  r  r  r  r  r  N)r3   	astra_env
collectionasync_collection)	ru   r  r  r  r  r  r  r  r  s	            rD   rv   zAstraDBCache.__init__Z  sT    L 7+%+"7!"7	
 	
 	
 .3 $ ?rF   ry   c                    | j                                          |                     ||          }| j                            d|iddi          d         d         }|t          |d                   nd S N_idr  rS  )filter
projectiondatar[  )r  ensure_db_setupr  r  find_onerm   ru   rw   rx   doc_idr   s        rD   r   zAstraDBCache.lookup  s    &&(((vz22''v Q	 ( 
 
   9=8H!${"3444dRrF   c                  K   | j                                          d {V  |                     ||          }| j                            d|iddi           d {V d         d         }|t          |d                   nd S r  )r  aensure_db_setupr  r  r  rm   r  s        rD   r   zAstraDBCache.alookup  s      n--/////////vz22'006  	 1         	 	 9=8H!${"3444dRrF   r   r&   rp   c                    | j                                          |                     ||          }t          |          }| j                            ||d           d S N)r  r  )r  r  r  ra   r  upsertru   rw   rx   r   r  r  s         rD   r   zAstraDBCache.update  sj    &&(((vz22!*--! 	
 	
 	
 	
 	
rF   c                   K   | j                                          d {V  |                     ||          }t          |          }| j                            ||d           d {V  d S r  )r  r  r  ra   r  r  r  s         rD   r   zAstraDBCache.aupdate  s       n--/////////vz22!*--#**! 
 
 	
 	
 	
 	
 	
 	
 	
 	
 	
rF   r   r)   r  r  c                    t          i |                                d|ig           d         }|                     ||          S r  r  r  s        rD   r  zAstraDBCache.delete_through_llm  r   rF   c                   K   t          i |                                d|ig            d{V d         }|                     ||           d{V S )z
        A wrapper around `adelete` with the LLM being passed.
        In case the llm.invoke(prompt) calls have a `stop` param, you should
        pass it here
        r  NrS  r  )r*   rK   rk  r  s        rD   adelete_through_llmz AstraDBCache.adelete_through_llm  s       0388::0&$0        
 \\&Z\@@@@@@@@@rF   c                    | j                                          |                     ||          }| j                            |           dS r  N)r  r  r  r  
delete_oneru   rw   rx   r  s       rD   r   zAstraDBCache.delete  sE    &&(((vz22""6*****rF   c                   K   | j                                          d{V  |                     ||          }| j                            |           d{V  dS r  )r  r  r  r  r  r  s       rD   rk  zAstraDBCache.adelete  sn      n--/////////vz22#..v66666666666rF   r   r
   c                j    | j                                          | j                                         d S r  r  r  r  r   r   s     rD   r   zAstraDBCache.clear  0    &&(((rF   c                   K   | j                                          d {V  | j                                         d {V  d S r  r  r  r  r   r   s     rD   r   zAstraDBCache.aclear  Y      n--/////////#))+++++++++++rF   r   )r  r<   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r   r  r  r  r   )r   r   r   r  r  &ASTRA_DB_CACHE_DEFAULT_COLLECTION_NAMEr  r   rv   r   r   r   r   r  r  r   rk  r   r   rJ   rF   rD   r  r  P  sd        6 6 6 \6  F#&*-18<#'&+%3%81@ 1@ 1@ 1@ 1@ 1@fS S S SS S S S	
 	
 	
 	

 
 
 
 BF: : : : : BFA A A A A + + + +7 7 7 7       , , , , , ,rF   r   langchain_astradb_semantic_cacheunsetc                  "    e Zd ZdZd	dZd
dZdS )_CachedAwaitablezECaches the result of an awaitable so it can be awaited multiple times	awaitableAwaitable[Any]c                ,    || _         t          | _        d S r  )r  _unsetresult)ru   r  s     rD   rv   z_CachedAwaitable.__init__  s    "rF   r=   r   c              #  x   K   | j         t          u r$| j                                        E d {V | _         | j         S r  )r  r  r  	__await__rt   s    rD   r  z_CachedAwaitable.__await__  sB      ;&  %)^%=%=%?%???????DK{rF   N)r  r  )r=   r   )r   r   r   r   rv   r  rJ   rF   rD   r  r    sB        OO        rF   r  funcr   c                >     t                     d fd            }|S )z7Makes an async function result awaitable multiple timesargsr
   r   r=   r  c                 .    t           | i |          S r  )r  )r  r   r  s     rD   wrapperz_reawaitable.<locals>.wrapper  s     d 5f 5 5666rF   )r  r
   r   r
   r=   r  )r   )r  r  s   ` rD   _reawaitabler  	  s:     4[[7 7 7 7 7 [7 NrF      Fr  r.  typedr  c                     d fd}|S )zdLeast-recently-used async cache decorator.
    Equivalent to functools.lru_cache for async functionsuser_functionr   r=   c                P     t                    t          |                     S r  )r   r  )r  r  r  s    rD   decorating_functionz-_async_lru_cache.<locals>.decorating_function  s%    (y%((m)D)DEEErF   )r  r   r=   r   rJ   )r  r  r  s   `` rD   r)  r)    s6    F F F F F F F rF   z&langchain_astradb.AstraDBSemanticCachec                      e Zd Zedddddej        dded
d7dZd8dZd8dZ	e
d9d            Zd:d"Zd:d#Zd;d%Zd;d&Zd<d(Zd<d)Z	 d=d>d.Z	 d=d>d/Zd?d1Zd?d2Zd@d5Zd@d6ZdS )AAstraDBSemanticCacheNF)
r  r  r  r  r  r  r  r  rQ  similarity_thresholdr  r<   r  r  r  r  r  r  r  r  r  r  r  r  r4  r(   rQ  r  r6  c                   |	 _         |
 _        | _        | _        t	          t
                    d
 fd            }| _        t          t
                    d
 fd            }| _        d}|t          j
        k    r                                 }n$|t          j        k    r                                 }t          ||||||||||
	
  
         _         j        j         _         j        j         _        dS )ab  
        Cache that uses Astra DB as a vector-store backend for semantic
        (i.e. similarity-based) lookup.

        It uses a single (vector) collection and can store
        cached values from several LLMs, so the LLM's 'llm_string' is stored
        in the document metadata.

        You can choose the preferred similarity (or use the API default).
        The default score threshold is tuned to the default metric.
        Tune it carefully yourself if switching to another distance metric.

        Args:
            collection_name: name of the Astra DB collection to create/use.
            token: API token for Astra DB usage.
            api_endpoint: full URL to the API endpoint,
                such as `https://<DB-ID>-us-east1.apps.astra.datastax.com`.
            astra_db_client: *alternative to token+api_endpoint*,
                you can pass an already-created 'astrapy.db.AstraDB' instance.
            async_astra_db_client: *alternative to token+api_endpoint*,
                you can pass an already-created 'astrapy.db.AsyncAstraDB' instance.
            namespace: namespace (aka keyspace) where the
                collection is created. Defaults to the database's "default namespace".
            setup_mode: mode used to create the Astra DB collection (SYNC, ASYNC or
                OFF).
            pre_delete_collection: whether to delete the collection
                before creating it. If False and the collection already exists,
                the collection will be used as is.
            embedding: Embedding provider for semantic encoding and search.
            metric: the function to use for evaluating similarity of text embeddings.
                Defaults to 'cosine' (alternatives: 'euclidean', 'dot_product')
            similarity_threshold: the minimum similarity for accepting a
                (semantic-search) match.
        r  r   r<   r=   r  c                :    j                             |           S r  r  r  s    rD   r  z7AstraDBSemanticCache.__init__.<locals>._cache_embedding^  r  rF   c                J   K   j                             |            d {V S r  r  r  s    rD   r   z8AstraDBSemanticCache.__init__.<locals>._acache_embeddingd  r!  rF   N)
r  r  r  r  r  r  r  r  r-  rQ  r&  )r4  rQ  r  r  r   ,ASTRA_DB_SEMANTIC_CACHE_EMBEDDING_CACHE_SIZEr(  r)  r*  r  r   r+  r   r,  r3   r  r  r  )ru   r  r  r  r  r  r  r  r  r4  rQ  r  r  r   r-  s   `              rD   rv   zAstraDBSemanticCache.__init__#  sJ   b #$8!. 
G	H	H	H	9 	9 	9 	9 	9 
I	H	9 /	"N	O	O	O	@ 	@ 	@ 	@ 	@ 
P	O	@  1@D---"&"@"@"B"B>..."&"?"?"A"A6+%+"7!"7 3
 
 
 .3 $ ?rF   r=   r.  c                H    t          |                     d                    S r0  r1  rt   s    rD   r,  z-AstraDBSemanticCache._get_embedding_dimension  r2  rF   c                X   K   t          |                     d           d {V           S r0  r4  rt   s    rD   r+  z.AstraDBSemanticCache._aget_embedding_dimension  r5  rF   rw   rx   c                D    t          |            dt          |           S r  r   r  s     rD   r  zAstraDBSemanticCache._make_id  r  rF   r   r&   rp   c                
   | j                                          |                     ||          }t          |          }|                     |          }t          |          }| j                            ||||d           d S Nr   )r  r  r>  z$vector)r  r  r  rE   r(  ra   r  r  ru   rw   rx   r   r  r>  r=  r?  s           rD   r   zAstraDBSemanticCache.update  s    &&(((vz22
++..F.;;!*--!#2+	 	
 	
 	
 	
 	
rF   c                2  K   | j                                          d {V  |                     ||          }t          |          }|                     |           d {V }t          |          }| j                            ||||d           d {V  d S r  )r  r  r  rE   r*  ra   r  r  r  s           rD   r   zAstraDBSemanticCache.aupdate  s       n--/////////vz22
++!%!5!56!5!B!BBBBBBB!*--#**!#2+	 
 
 	
 	
 	
 	
 	
 	
 	
 	
 	
rF   ry   c                F    |                      ||          }||d         S d S rB  rC  rE  s       rD   r   zAstraDBSemanticCache.lookup  rG  rF   c                V   K   |                      ||           d {V }||d         S d S rB  rI  rE  s       rD   r   zAstraDBSemanticCache.alookup  rK  rF   rL  c                2   | j                                          |                     |          }t          |          }| j                            |d|iddgd          }||d         | j        k     rdS t          |d                   }|
|d         |fS dS )	
        Look up based on prompt and llm_string.
        If there are hits, return (document_id, cached_entry) for the top hit
        r   r>  r  r  Tr:  r  fieldsinclude_similarityN$similarity)r  r  r(  rE   r  vector_find_oner  rm   ru   rw   rx   rV  r>  rX  rG   s          rD   rD  z#AstraDBSemanticCache.lookup_with_id  s     	&&((((,(;(;(;(H(H
++o--#!?  '# . 
 
 ;#m,t/HHH4,S-=>>K&5z;..trF   c                Z  K   | j                                          d{V  |                     |           d{V }t          |          }| j                            |d|iddgd           d{V }||d         | j        k     rdS t          |d                   }|
|d         |fS dS )	r  Nr   r>  r  r  Tr  r  )r  r  r*  rE   r  r  r  rm   r  s          rD   rJ  z$AstraDBSemanticCache.alookup_with_id  s      n--/////////.2.B.B.B.O.O(O(O(O(O(O(O
++)99#!?  '# : 
 
 
 
 
 
 
 
 ;#m,t/HHH4,S-=>>K&5z;..trF   r   r)   r  r  c                    t          i |                                d|ig           d         }|                     ||          S r\  r]  r  s        rD   r^  z/AstraDBSemanticCache.lookup_with_id_through_llm  r_  rF   c                   K   t          i |                                d|ig            d {V d         }|                     ||           d {V S r\  ra  r  s        rD   rb  z0AstraDBSemanticCache.alookup_with_id_through_llm  rc  rF   rd  c                l    | j                                          | j                            |           dS rg  N)r  r  r  r  rh  s     rD   ri  z*AstraDBSemanticCache.delete_by_document_id	  s4     	&&((("";/////rF   c                   K   | j                                          d{V  | j                            |           d{V  dS r  )r  r  r  r  rh  s     rD   rl  z+AstraDBSemanticCache.adelete_by_document_id  s]       n--/////////#..{;;;;;;;;;;;rF   r   r
   c                j    | j                                          | j                                         d S r  r  r   s     rD   r   zAstraDBSemanticCache.clear  r  rF   c                   K   | j                                          d {V  | j                                         d {V  d S r  r  r   s     rD   r   zAstraDBSemanticCache.aclear  r  rF   )r  r<   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r4  r(   rQ  r  r  r6  rp  r   r   r   rq  r  rr  rs  r   )r   r   r   r  r  r   )ASTRA_DB_SEMANTIC_CACHE_DEFAULT_THRESHOLDrv   r,  r+  r  r  r   r   r   r   rD  rJ  r^  rb  ri  rl  r   r   rJ   rF   rD   r  r    s         F#&*-18<#'%3%8&+ $&OZ@ Z@ Z@ Z@ Z@ Z@xK K K KR R R R 6 6 6 \6
 
 
 
 
 
 
 
$         <   > BFB B B B B BF	I 	I 	I 	I 	I0 0 0 0< < < <       , , , , , ,rF   r  c                      e Zd ZdZdZdZddej        ej	        dddd	dd
d
d5d!Z
d6d$Zd7d&Zd8d)Zd9d-Zd:d0Zed;d4            ZdS )<AzureCosmosDBSemanticCachez:Cache that uses Cosmos DB Mongo vCore vector-store backendCosmosMongoVCoreCacheDBCosmosMongoVCoreCacheCollNd   i   r  @   (   LANGCHAIN_CACHING_PYTHON)
cosmosdb_client	num_lists
similaritykind
dimensionsmef_construction	ef_searchr5  application_namecosmosdb_connection_stringr<   database_namer  r4  r(   r  Optional[Any]r  r.  r  r    r  r!   r  r  r  r  r5  Optional[float]r  c       
           |                      |t                     |                      |t                     |st          d          || _        || _        || _        |p| j        | _        |p| j	        | _
        || _        |	| _        || _        || _        |
| _        || _        || _        || _        i | _        || _        dS )a
  
        Args:
            cosmosdb_connection_string: Cosmos DB Mongo vCore connection string
            cosmosdb_client: Cosmos DB Mongo vCore client
            embedding (Embedding): Embedding provider for semantic encoding and search.
            database_name: Database name for the CosmosDBMongoVCoreSemanticCache
            collection_name: Collection name for the CosmosDBMongoVCoreSemanticCache
            num_lists: This integer is the number of clusters that the
                inverted file (IVF) index uses to group the vector data.
                We recommend that numLists is set to documentCount/1000
                for up to 1 million documents and to sqrt(documentCount)
                for more than 1 million documents.
                Using a numLists value of 1 is akin to performing
                brute-force search, which has limited performance
            dimensions: Number of dimensions for vector similarity.
                The maximum number of supported dimensions is 2000
            similarity: Similarity metric to use with the IVF index.

                Possible options are:
                    - CosmosDBSimilarityType.COS (cosine distance),
                    - CosmosDBSimilarityType.L2 (Euclidean distance), and
                    - CosmosDBSimilarityType.IP (inner product).
            kind: Type of vector index to create.
                Possible options are:
                    - vector-ivf
                    - vector-hnsw: available as a preview feature only,
                                   to enable visit https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/preview-features
            m: The max number of connections per layer (16 by default, minimum
               value is 2, maximum value is 100). Higher m is suitable for datasets
               with high dimensionality and/or high accuracy requirements.
            ef_construction: the size of the dynamic candidate list for constructing
                            the graph (64 by default, minimum value is 4, maximum
                            value is 1000). Higher ef_construction will result in
                            better index quality and higher accuracy, but it will
                            also increase the time required to build the index.
                            ef_construction has to be at least 2 * m
            ef_search: The size of the dynamic candidate list for search
                       (40 by default). A higher value provides better
                       recall at the cost of speed.
            score_threshold: Maximum score used to filter the vector search documents.
            application_name: Application name for the client for tracking and logging
        z) CosmosDB connection string can be empty.N)_validate_enum_valuer    r!   r[   r  r  r4  DEFAULT_DATABASE_NAMEr  DEFAULT_COLLECTION_NAMEr  r  r  r  r  r  r  r  r5  r8  r  )ru   r  r  r  r4  r  r  r  r  r  r  r  r  r5  r  s                  rD   rv   z#AzureCosmosDBSemanticCache.__init__*  s    z 	!!*.DEEE!!$(@AAA) 	JHIII*D'."*Hd.H.N$2N"$$	.".AC 0rF   rx   r=   c                *    t          |          }d| S r:  r   r;  s      rD   r=  z&AzureCosmosDBSemanticCache._index_name}  r>  rF   r4   c                   |                      |          }| j        dz   | j        z   }|| j        v r| j        |         S | j        r=| j        | j                 | j                 }t          || j        |          | j        |<   n0t          j        | j        || j        || j	                  | j        |<   | j        |         }|
                                s8|                    | j        | j        | j        | j        | j        | j                   |S )Nr  )r  r4  rA  )connection_stringr  r4  rA  r  )r=  r  r  r8  r  r4   r4  from_connection_stringr  r  index_existscreate_indexr  r  r  r  r  r  )ru   rx   rA  r  r  vectorstores         rD   rL  z)AzureCosmosDBSemanticCache._get_llm_cache  s4   %%j11
&,t/CC	 )))#J//  	-d.@A$BVWJ+D%.%, , ,DZ(( *@&*&E'"n)%)%:   Z( &z2'')) 	$$	$   rF   rw   ry   c                   |                      |          }g }|                    |d| j        | j        | j                  }|r|D ]}	 |                    t          |j        d                              1# t          $ rJ t          
                    d           |                    t          |j        d                              Y w xY w|r|ndS )r|   rS  )r   rT  r  r  r5  r   r   N)rL  rW  r  r  r5  rX  r/   r   r   rj   rk   r]   rY  s          rD   r   z!AzureCosmosDBSemanticCache.lookup  s   ''
33	--n 0 . 
 
  	#  &&uX->|-L'M'MNNNN    NN!    &&3H4El4STT     *3{{t3s   -A66AC
	C
r   r&   rp   c                   |D ]6}t          |t                    st          dt          |                     7|                     |          }||t          d |D                       d}|                    |g|g           dS )r   zUCosmosDBMongoVCoreSemanticCache only supports caching of normal LLM generations, got c                    g | ]}|S rJ   rJ   r_  s     rD   rN   z5AzureCosmosDBSemanticCache.update.<locals>.<listcomp>  ra  rF   rb  rc  Nrf  rh  s          rD   r   z!AzureCosmosDBSemanticCache.update  s     	 	Cc:..  ?3799? ?   ''
33	$ 7 7J 7 7 788
 

 	6(xjAAAAArF   r   r
   c                    |                      |d                   }|| j        v r4| j        |                                                             i            dS dS rN  rx   N)r=  r8  get_collectiondelete_manyrQ  s      rD   r   z AzureCosmosDBSemanticCache.clear  s^    %%f\&:;;
)))Z(7799EEbIIIII *)rF   r  	enum_type
Type[Enum]c                R    t          | |          st          d|  d| d          d S )NzInvalid enum value: z. Expected r  )r   r[   )r  r*  s     rD   r  z/AzureCosmosDBSemanticCache._validate_enum_value  sC    %++ 	TRERRiRRRSSS	T 	TrF   )r  r<   r  r<   r  r<   r4  r(   r  r  r  r.  r  r    r  r!   r  r.  r  r.  r  r.  r  r.  r5  r  r  r<   rj  )rx   r<   r=   r4   r   r   r   )r  r
   r*  r+  r=   rp   )r   r   r   r   r  r  r    COSr!   
VECTOR_IVFrv   r=  rL  r   r   r   r  r  rJ   rF   rD   r  r  $  s       DD59 *.-C-G)A)L!+/ :!Q1 Q1 Q1 Q1 Q1 Q1f' ' ' '( ( ( (T4 4 4 4<B B B B"J J J J T T T \T T TrF   r  c                  F    e Zd ZdZ	 dddZddZddZddZddZd dZ	dS )!OpenSearchSemanticCachez/Cache that uses OpenSearch vector store backendr2  opensearch_urlr<   r4  r(   r5  r6  r   r
   c                L    i | _         || _        || _        || _        || _        dS )aQ  
        Args:
            opensearch_url (str): URL to connect to OpenSearch.
            embedding (Embedding): Embedding provider for semantic encoding and search.
            score_threshold (float, 0.2):
        Example:
        .. code-block:: python
            import langchain
            from langchain.cache import OpenSearchSemanticCache
            from langchain.embeddings import OpenAIEmbeddings
            langchain.llm_cache = OpenSearchSemanticCache(
                opensearch_url="http//localhost:9200",
                embedding=OpenAIEmbeddings()
            )
        N)r8  r1  r4  r5  connection_kwargs)ru   r1  r4  r5  r   s        rD   rv   z OpenSearchSemanticCache.__init__  s2    , >@,".!'rF   rx   r=   c                *    t          |          }d| S )Ncache_r   r;  s      rD   r=  z#OpenSearchSemanticCache._index_name	  r>  rF   OpenSearchVectorStorec                h   |                      |          }|| j        v r| j        |         S t          d| j        || j        d| j        | j        |<   | j        |         }|                                s>| j                            d          }|                    t          |          |           |S )N)r1  rA  embedding_functionrD  r   rJ   )
r=  r8  r6  r1  r4  r3  r   rH  r!  rJ  )ru   rx   rA  r"  rK  s        rD   rL  z&OpenSearchSemanticCache._get_llm_cache
	  s    %%j11
 )))#J// (= (
.!#~(
 (
 $	(
 (
$ &z2'')) 	B333@@J$$S__jAAArF   rw   ry   c                   |                      |          }g }|                    |d| j                  }|r|D ]}	 |                    t	          |j        d                              1# t          $ rJ t                              d           |                    t          |j        d                              Y w xY w|r|ndS )r|   rS  )r   rT  r5  r   r   NrV  rY  s          rD   r   zOpenSearchSemanticCache.lookup 	  s   ''
33	-- 0 . 
 

  	#  &&uX->|-L'M'MNNNN  
 
 
NN!    &&3H4El4STT    
 *3{{t3r\  r   r&   rp   c                   |D ]6}t          |t                    st          dt          |                     7|                     |          }||t          d |D                       d}|                    |g|g           dS )r   zMOpenSearchSemanticCache only supports caching of normal LLM generations, got c                    g | ]}|S rJ   rJ   r_  s     rD   rN   z2OpenSearchSemanticCache.update.<locals>.<listcomp>G	  ra  rF   rb  rc  Nrf  rh  s          rD   r   zOpenSearchSemanticCache.update;	       	 	Cc:..  ?3799? ?  
 ''
33	$ 7 7J 7 7 788
 

 	6(xjAAAAArF   c                    |                      |d                   }|| j        v r+| j        |                             |           | j        |= dS dS )rN  rx   )rA  N)r=  r8  delete_indexrQ  s      rD   r   zOpenSearchSemanticCache.clearK	  s`    %%f\&:;;
)))Z(555LLL ,,, *)rF   Nri  )r1  r<   r4  r(   r5  r6  r   r
   rj  )rx   r<   r=   r6  r   r   r   
r   r   r   r   rv   r=  rL  r   r   r   rJ   rF   rD   r0  r0    s        99 "%	( ( ( ( (8' ' ' '   ,4 4 4 46B B B B - - - - - -rF   r0  c                  J    e Zd ZdZdddddZddZddZddZd dZd!dZ	dS )"SingleStoreDBSemanticCachez+Cache that uses SingleStore DB as a backendr5  r2  )cache_table_prefixsearch_thresholdr4  r(   rB  r<   rC  r6  r   r
   c               L    i | _         || _        || _        || _        || _        dS )a  Initialize with necessary components.

        Args:
            embedding (Embeddings): A text embedding model.
            cache_table_prefix (str, optional): Prefix for the cache table name.
                Defaults to "cache_".
            search_threshold (float, optional): The minimum similarity score for
                a search result to be considered a match. Defaults to 0.2.

            Following arguments pertrain to the SingleStoreDB vector store:

            distance_strategy (DistanceStrategy, optional):
                Determines the strategy employed for calculating
                the distance between vectors in the embedding space.
                Defaults to DOT_PRODUCT.
                Available options are:
                - DOT_PRODUCT: Computes the scalar product of two vectors.
                    This is the default behavior
                - EUCLIDEAN_DISTANCE: Computes the Euclidean distance between
                    two vectors. This metric considers the geometric distance in
                    the vector space, and might be more suitable for embeddings
                    that rely on spatial relationships. This metric is not
                    compatible with the WEIGHTED_SUM search strategy.

            content_field (str, optional): Specifies the field to store the content.
                Defaults to "content".
            metadata_field (str, optional): Specifies the field to store metadata.
                Defaults to "metadata".
            vector_field (str, optional): Specifies the field to store the vector.
                Defaults to "vector".
            id_field (str, optional): Specifies the field to store the id.
                Defaults to "id".

            use_vector_index (bool, optional): Toggles the use of a vector index.
                Works only with SingleStoreDB 8.5 or later. Defaults to False.
                If set to True, vector_size parameter is required to be set to
                a proper value.

            vector_index_name (str, optional): Specifies the name of the vector index.
                Defaults to empty. Will be ignored if use_vector_index is set to False.

            vector_index_options (dict, optional): Specifies the options for
                the vector index. Defaults to {}.
                Will be ignored if use_vector_index is set to False. The options are:
                index_type (str, optional): Specifies the type of the index.
                    Defaults to IVF_PQFS.
                For more options, please refer to the SingleStoreDB documentation:
                https://docs.singlestore.com/cloud/reference/sql-reference/vector-functions/vector-indexing/

            vector_size (int, optional): Specifies the size of the vector.
                Defaults to 1536. Required if use_vector_index is set to True.
                Should be set to the same value as the size of the vectors
                stored in the vector_field.

            Following arguments pertain to the connection pool:

            pool_size (int, optional): Determines the number of active connections in
                the pool. Defaults to 5.
            max_overflow (int, optional): Determines the maximum number of connections
                allowed beyond the pool_size. Defaults to 10.
            timeout (float, optional): Specifies the maximum wait time in seconds for
                establishing a connection. Defaults to 30.

            Following arguments pertain to the database connection:

            host (str, optional): Specifies the hostname, IP address, or URL for the
                database connection. The default scheme is "mysql".
            user (str, optional): Database username.
            password (str, optional): Database password.
            port (int, optional): Database port. Defaults to 3306 for non-HTTP
                connections, 80 for HTTP connections, and 443 for HTTPS connections.
            database (str, optional): Database name.

            Additional optional arguments provide further customization over the
            database connection:

            pure_python (bool, optional): Toggles the connector mode. If True,
                operates in pure Python mode.
            local_infile (bool, optional): Allows local file uploads.
            charset (str, optional): Specifies the character set for string values.
            ssl_key (str, optional): Specifies the path of the file containing the SSL
                key.
            ssl_cert (str, optional): Specifies the path of the file containing the SSL
                certificate.
            ssl_ca (str, optional): Specifies the path of the file containing the SSL
                certificate authority.
            ssl_cipher (str, optional): Sets the SSL cipher list.
            ssl_disabled (bool, optional): Disables SSL usage.
            ssl_verify_cert (bool, optional): Verifies the server's certificate.
                Automatically enabled if ``ssl_ca`` is specified.
            ssl_verify_identity (bool, optional): Verifies the server's identity.
            conv (dict[int, Callable], optional): A dictionary of data conversion
                functions.
            credential_type (str, optional): Specifies the type of authentication to
                use: auth.PASSWORD, auth.JWT, or auth.BROWSER_SSO.
            autocommit (bool, optional): Enables autocommits.
            results_type (str, optional): Determines the structure of the query results:
                tuples, namedtuples, dicts.
            results_format (str, optional): Deprecated. This option has been renamed to
                results_type.

        Examples:
            Basic Usage:

            .. code-block:: python

                import langchain
                from langchain.cache import SingleStoreDBSemanticCache
                from langchain.embeddings import OpenAIEmbeddings

                langchain.llm_cache = SingleStoreDBSemanticCache(
                    embedding=OpenAIEmbeddings(),
                    host="https://user:password@127.0.0.1:3306/database"
                )

            Advanced Usage:

            .. code-block:: python

                import langchain
                from langchain.cache import SingleStoreDBSemanticCache
                from langchain.embeddings import OpenAIEmbeddings

                langchain.llm_cache = = SingleStoreDBSemanticCache(
                    embeddings=OpenAIEmbeddings(),
                    use_vector_index=True,
                    host="127.0.0.1",
                    port=3306,
                    user="user",
                    password="password",
                    database="db",
                    table_name="my_custom_table",
                    pool_size=10,
                    timeout=60,
                )
        N)r8  r4  rB  rC  r3  )ru   r4  rB  rC  r   s        rD   rv   z#SingleStoreDBSemanticCache.__init__V	  s4    b 68""4 0 "(rF   rx   r=   c                6    t          |          }| j         | S r  )rE   rB  r;  s      rD   r=  z&SingleStoreDBSemanticCache._index_name	  s#    Z(()9<999rF   r8   c                    |                      |          }|| j        vr!t          d| j        |d| j        | j        |<   | j        |         S )N)r4  r  rJ   )r=  r8  r8   r4  r3  )ru   rx   rA  s      rD   rL  z)SingleStoreDBSemanticCache._get_llm_cache	  sk    %%j11
 T---+8 ,.%, , (, ,DZ(
 
++rF   rw   ry   c                v   |                      |          }g }|                    |d          }|r|D ]}|d         | j        k    r|j        t          j        k    s&|d         | j        k     rH|j        t          j        k    r3|                    t          |d         j	        d                              |r|ndS )r|   rS  )r   rT  r   r   N)
rL  similarity_search_with_scorerC  distance_strategyr"   DOT_PRODUCTEUCLIDEAN_DISTANCErX  r/   r   )ru   rw   rx   rZ  rG   r\   document_scores          rD   r   z!SingleStoreDBSemanticCache.lookup	  s    ''
33	88 9 
 
  
	X") 	X 	X"1%(===!37G7SSS"1%(===!3':; ;  &&u^A->-G-U'V'VWWW)3{{t3rF   r   r&   rp   c                   |D ]6}t          |t                    st          dt          |                     7|                     |          }||t          d |D                       d}|                    |g|g           dS )r   zPSingleStoreDBSemanticCache only supports caching of normal LLM generations, got c                    g | ]}|S rJ   rJ   r_  s     rD   rN   z5SingleStoreDBSemanticCache.update.<locals>.<listcomp>!
  ra  rF   rb  rc  Nrf  rh  s          rD   r   z!SingleStoreDBSemanticCache.update
  r<  rF   c                    |                      |d                   }|| j        v r)| j        |                                          | j        |= dS dS r'  )r=  r8  droprQ  s      rD   r   z SingleStoreDBSemanticCache.clear%
  s[    %%f\&:;;
)))Z(--/// ,,, *)rF   N)r4  r(   rB  r<   rC  r6  r   r
   rj  )rx   r<   r=   r8   r   r   r   r?  rJ   rF   rD   rA  rA  S	  s        55 #+"%W( W( W( W( W( W(r: : : :
, 
, 
, 
,4 4 4 4,B B B B - - - - - -rF   rA  c                  2    e Zd ZdZddZdd
ZddZddZdS )MemcachedCachez?Cache that uses Memcached backend through pymemcache client libclient_r
   c                   	 ddl m}m}m}m} n$# t
          t          f$ r t          d          w xY wt          ||          s?t          ||          s/t          ||          st          ||          st          d          || _	        dS )ay  
        Initialize an instance of MemcachedCache.

        Args:
            client_ (str): An instance of any of pymemcache's Clients
                (Client, PooledClient, HashClient)
        Example:
        .. code-block:: python
            ifrom langchain.globals import set_llm_cache
            from langchain_openai import OpenAI

            from langchain_community.cache import MemcachedCache
            from pymemcache.client.base import Client

            llm = OpenAI(model="gpt-3.5-turbo-instruct", n=2, best_of=2)
            set_llm_cache(MemcachedCache(Client('localhost')))

            # The first time, it is not yet in cache, so it should take longer
            llm.invoke("Which city is the most crowded city in the USA?")

            # The second time it is, so it goes faster
            llm.invoke("Which city is the most crowded city in the USA?")
        r   )Client
HashClientPooledClientRetryingClientz_Could not import pymemcache python package. Please install it with `pip install -U pymemcache`.z&Please pass a valid pymemcached clientN)
pymemcache.clientrU  rV  rW  rX  r   r  r   r[   client)ru   rS  rU  rV  rW  rX  s         rD   rv   zMemcachedCache.__init__0
  s    2	             01 	 	 	F  	 w''	G'<00	G ':..	G '>22		G EFFFs    !0rw   r<   rx   r=   ry   c                    t          ||z             }	 | j                            |          }n# t          j        $ r Y dS w xY w|t          |          ndS r{   )rE   rZ  r}   
pymemcacheMemcacheErrorrm   )ru   rw   rx   r   r  s        rD   r   zMemcachedCache.lookup`
  sn    FZ'((	[__S))FF' 	 	 	44	 .4-?!&)))TIs   / AAr   r&   rp   c                    t          ||z             }|D ]9}t          |t                    s"t          ddt	          |           z             :t          |          }| j                            ||           dS )r   z;Memcached only supports caching of normal LLM generations, zgot N)rE   r   r1   r[   r   ra   rZ  r  )ru   rw   rx   r   r   r   r  s          rD   r   zMemcachedCache.updatej
  s    FZ'((  	 	Cc:..  Q(T#YY(()   #:..U#####rF   r   c                    |                     dd          }|                     dd          }| j                            ||           dS )aq  
        Clear the entire cache. Takes optional kwargs:

        delay: optional int, the number of seconds to wait before flushing,
                or zero to flush immediately (the default). NON-BLOCKING, returns
                immediately.
        noreply: optional bool, True to not wait for the reply (defaults to
                client.default_noreply).
        delayr   noreplyN)r}   rZ  	flush_all)ru   r   r`  ra  s       rD   r   zMemcachedCache.clearz
  sH     

7A&&**Y--eW-----rF   N)rS  r
   r   r   r   r  rJ   rF   rD   rR  rR  -
  so        II. . . .`J J J J$ $ $ $ . . . . . .rF   rR  )r;   r<   r=   r<   )rG   r&   r=   r<   )rS   r<   r=   r&   )rb   r<   r=   rc   )r  r  r  r<   r=   rp   )r   r  r=   rp   )r  r   r=   r   )r  F)r  r.  r  r  r=   r   )r   
__future__r   r@   r~  rP   loggingr  r   abcr   datetimer   enumr   	functoolsr   r   typingr	   r
   r   r   r   r   r   r   r   r   r   r   r   
sqlalchemyr   r   r   r   r   r   sqlalchemy.enginer   sqlalchemy.engine.baser   sqlalchemy.ormr   'langchain_community.utilities.cassandrar   r  0langchain_community.vectorstores.azure_cosmos_dbr    r!   &langchain_community.vectorstores.utilsr"   r#   r   sqlalchemy.ext.declarativelangchain_core._api.deprecationr$   r%   langchain_core.cachesr&   r'   langchain_core.embeddingsr(   #langchain_core.language_models.llmsr)   r*   r+   langchain_core.load.dumpr-   langchain_core.load.loadr/   langchain_core.outputsr0   r1   langchain_core.utilsr2   %langchain_community.utilities.astradbr  r3    langchain_community.vectorstoresr4   r5   r6  &langchain_community.vectorstores.redisr7   r?  .langchain_community.vectorstores.singlestoredbr8   	getLogger__file__rj   r  r\  
astrapy.dbr9   r:   cassandra.clusterCassandraSessionrE   rR   r]   ra   rm   ro   Baser   r   r   r   r   r  r!  r.  rl  r  r  r  r  r	  r  rw  ru  rt  rv  r'  r  ry  r  r  r  r  r  r  r  r  r)  r  r  r0  rA  rR  rJ   rF   rD   <module>r     s	   , # " " " " "                         & & & & & & & &                               N M M M M M M M M M M M M M M M ! ! ! ! ! ! ) ) ) ) ) ) " " " " " " S S S S S S        D C C C C C</////// < < <;;;;;;;;< H G G G G G G G < < < < < < < < 0 0 0 0 0 0 N N N N N N N N N N * * * * * * * * * * * * = = = = = = = = - - - - - -           G F F F F F      M L L L L L H H H H H H		8	$	$ >NNN00000000======4 4 4 4
I I I I
 
 
 
.? ? ? ?($ $ $ $N    I   D     4   0 0 0 0 0i 0 0 0f! ! ! ! !/ ! ! !S4 S4 S4 S4 S4	 S4 S4 S4l/" /" /" /" /"i /" /" /"d?5 ?5 ?5 ?5 ?5 ?5 ?5 ?5DY; Y; Y; Y; Y;o Y; Y; Y;xB B B B B B B BDy# y# y# y# y#y y# y# y#xX X X X(A A A A
`1 `1 `1 `1 `19 `1 `1 `1F &; "&* #Z% Z% Z% Z% Z%Y Z% Z% Z%| 49 037 0.L +/3 ,02 -~" ~" ~" ~" ~"Y ~" ~" ~"B
	 	 	 	 	d 	 	 	A> A> A> A> A> A> A> A>H *C & 
7  
\, \, \, \, \,9 \, \, 
\,~ -1 ))K &/1 , 
 
 
 
 
 
 
 
        
?  
, , , , ,9 , , 
,D@T @T @T @T @T @T @T @TFi- i- i- i- i-i i- i- i-XW- W- W- W- W- W- W- W-tZ. Z. Z. Z. Z.Y Z. Z. Z. Z. Z.s   B B%$B%