o
    ÚŠTjV  ã                   @  sf   d Z ddlmZ ddlZddlmZ ddlmZmZ ddl	Z
ddlmZ ddlmZ G d	d
„ d
ƒZdS )u×  Semantic cache â€” the biggest energy lever.

Before we retrieve or call the GPU, we check whether a semantically-equivalent question was
already answered. If a stored query's embedding is within `similarity_threshold` cosine distance,
we return the cached answer and skip the model entirely.

The store is a small JSON file: parallel lists of embeddings, queries, and answer payloads.
For very large caches, swap this for a FAISS index â€” the interface stays the same.
é    )ÚannotationsN)ÚPath)ÚAnyÚOptionalé   )ÚEmbedder)ÚConfigc                   @  s:   e Zd Zddd„Zdd„ Zdd„ Zddd„Zddd„ZdS )ÚSemanticCacheÚcfgr   c                 C  sZ   t | dd¡ƒ| _t| dd¡ƒ| _| dd¡| _t|ƒ| _d | _	g | _
g | _|  ¡  d S )Nzcache.enabledTzcache.similarity_thresholdgq=
×£pí?z
cache.pathzcache_store.json)ÚboolÚgetÚenabledÚfloatÚ	thresholdZresolveÚpathr   ÚembedderÚ_vecsÚ_queriesÚ	_payloadsÚ_load)Úselfr
   © r   úsrc/agent/cache.pyÚ__init__   s   
zSemanticCache.__init__c                 C  s’   | j  ¡ sd S t| j ddd��}t |¡}W d   ƒ n1 sw   Y  | dg ¡| _| dg ¡| _| dg ¡}|rDtj	|dd�| _
d S d | _
d S )	NÚrúutf-8©ÚencodingÚqueriesÚpayloadsÚvectorsZfloat32)Zdtype)r   ÚexistsÚopenÚjsonÚloadr   r   r   ÚnpZarrayr   )r   ÚfÚstoreZvecsr   r   r   r   !   s   
ÿ"zSemanticCache._loadc                 C  s|   | j | j| jd u rg n| j ¡ dœ}| jjjddd� t| jddd��}tj	||dd� W d   ƒ d S 1 s7w   Y  d S )	N)r   r   r    T)ÚparentsÚexist_okÚwr   r   F)Zensure_ascii)
r   r   r   Útolistr   ÚparentÚmkdirr"   r#   Údump)r   r'   r&   r   r   r   Ú_persist+   s   ý"ÿzSemanticCache._persistÚqueryÚstrÚreturnúOptional[dict]c                 C  sŒ   | j r| jdu st| jƒdkrdS | j |¡}| j| }tt |¡ƒ}t	|| ƒ| j
krDt| j| ƒ}t	|| ƒ|d< | j| |d< |S dS )zGReturn the cached payload for a semantically-equivalent query, or None.Nr   Z_cache_similarityZ_cache_matched_query)r   r   Úlenr   r   Úembed_queryÚintr%   Zargmaxr   r   Údictr   )r   r0   ÚqvecZsimsZbestZhitr   r   r   Úlookup5   s   
zSemanticCache.lookupÚpayloadúdict[str, Any]ÚNonec                 C  sb   | j sd S | j |¡ dd¡}| jd u r|nt | j|g¡| _| j |¡ | j	 |¡ |  
¡  d S )Nr   éÿÿÿÿ)r   r   r5   Zreshaper   r%   Zvstackr   Úappendr   r/   )r   r0   r:   r8   r   r   r   r'   C   s    zSemanticCache.storeN)r
   r   )r0   r1   r2   r3   )r0   r1   r:   r;   r2   r<   )Ú__name__Ú
__module__Ú__qualname__r   r   r/   r9   r'   r   r   r   r   r	      s    




r	   )Ú__doc__Z
__future__r   r#   Zpathlibr   Útypingr   r   Znumpyr%   Z
embeddingsr   Zsettingsr   r	   r   r   r   r   Ú<module>   s    	